Been on the road pretty much non-stop since January, so I haven't had the opportunity to post as much as I'd like. However, it looks like the next couple of months will be a little more reasonable in terms of the travel schedule, so I should be able to clear out a bit of the backlog of strange and interesting posts about RFID, BizTalk Server, and other bits of Microsoft technology.
I've always been a scripting guy, going back almost 15 years to being a pretty hard core UNIX sysadmin. Cut my teeth on perl4, and every manner of shell scripting under the sun (as well as some that should never have seen the light of day). Although I no longer have much (any) claim to vi wizardry (I'll keep my Visual Studio thank you very much) one of the aspects of the *NIX environment that I'd always missed was a rich scripting and automation interface. With the release of PowerShell, the Windows platform has an amazing scripting environment that combines much of the magic of other scripting hosts, as well as some truly unique features leveraging the .NET platform.
If you've never been exposed to PowerShell before, I highly recommend checking out the following:
When deploying and managing (troubleshooting!) BizTalk RFID installations, there is often the need to automate certain tasks. BizTalk RFID ships with a command line utility (rfidclientconsole.exe), but this isn't well suited to adhoc tasks and quick scripting, as it relies heavily on the use of parameter passing via complicated XML files. Happily, PowerShell is very well suited to wrapping up .NET API's and making them consumable with rich parameters and aggregation.
The intent is to publish a series of blog posts on using PowerShell and RFID, and gradually build up a library of cmdlets that can be used to administer BizTalk RFID installations.
Source Code Package here.
In this first post we'll pick off some low-hanging fruit - the ability to get information about providers and server configuration, then create some code to perform a basic sysadmin task - changing the log level of a provider or process component programatically. Following the usual PowerShell naming conventions, we will create the following cmdlets (mimicking functionality of the rfidclientconsole application, only with a rich parameter experience):
To get started on creating PowerShell cmdlets, read the following excellent blog posts:
The samples in the rest of this post will use the PowerShell templates and debugging techniques from these posts. To get started:
NOTE: If you are running on a 64-bit system, you need to GAC the output assembly with both the 32-bit and 64-bit versions of installutil.exe. Do that with a post-build event command lineof:
c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\installutil.exe $(TargetDir)$(TargetFileName) c:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\installutil.exe $(TargetDir)$(TargetFileName)
We'll start with a fairly simple cmdlet - retrieving the status of a set of providers, leveraging the GetProviderStatus() API call. The cmdlet should be able to take in the name (or names of a set) of a provider as well as a target server. The signature of the cmdlet will be:
Get-RfidProviderStatus [Provider Names] [-Server servername]
1. Start off by adding a new Cmdlet to the project, under Add, New Item, Windows PowerShell, Windows PowerShell Cmdlet. Name it GetRfidProviderStatusCmdlet.cs.
2. Add the following references to the project, from the C:\Program Files\Microsoft Biztalk RFID\bin\ directory.
Microsoft.Rfid.Client.dll Microsoft.Rfid.Design.dll Microsoft.Rfid.ManagementWebServices.dll Microsoft.Rfid.SpiSdk.dll
3. Add the following using statements to the top of the class file:
using Microsoft.SensorServices.Rfid.Runtime; using Microsoft.SensorServices.Rfid.Management;
4. Change the class Cmdlet attribute to reflect the desired name of the cmdlet. Note that since this cmdlet does not have any impact on the system (i.e. doesn't change anything), we can set the SupportsShouldProcess value to false.
[Cmdlet(VerbsCommon.Get, "RfidProviderStatus", SupportsShouldProcess = false)] public class GetRfidProviderCmdlet : Cmdlet
4. Define the parameters, as per the following code. This will define two parameters, ProviderName (an array of strings to represent the provider name), and Server (a single string to represent the target BizTalk RFID server).
1: [Parameter(Position = 0,
2: Mandatory = false,
3: ValueFromPipelineByPropertyName = true,
4: HelpMessage = "The name (or names) of the target providers")]
5: [ValidateNotNullOrEmpty]
6: [Alias("name")]
7: public string[] ProviderName
8: {
9: get;
10: set;
11: }
12:
13: [Parameter(Position = 1,
14: Mandatory = false,
15: ValueFromPipelineByPropertyName = true,
16: HelpMessage = "The name (or names) of the target BizTalk RFID server")]
17: [ValidateNotNullOrEmpty]
18: public string Server
19: {
20: get;
21: set;
22: }
5. Override the BeginProcessing method to create initialization code which will create the ProviderManagerProxy object pointing to the appropriate server.
1: private ProviderManagerProxy provProxy;
2:
3: protected override void BeginProcessing()
4: {
5: if (String.IsNullOrEmpty(this.Server))
6: provProxy = new ProviderManagerProxy();
7: else
8: provProxy = new ProviderManagerProxy(this.Server);
9: }
6. Now the meat of the whole cmdlet development exercise - actually reaching out to the BizTalk RFID server and retrieving the provider status information. Create an override for the ProcessRecord method, as per:
1: protected override void ProcessRecord()
2: {
3: try
5: if (ProviderName == null || ProviderName.Length == 0)
6: WriteVerbose("Retrieving status for all providers");
8: WriteVerbose("Retrieving status for providers " + String.Join(",", ProviderName));
9:
10: ProviderStatus[] provStatus = provProxy.GetProviderStatus(ProviderName);
11: WriteObject(provStatus, true);
12: }
13: catch (RfidClientException ex0)
14: {
15: ApplicationException ex_app = new ApplicationException(ex0.RemoteErrorMessage, ex0);
16: WriteError(new ErrorRecord(ex_app, ex0.RemoteErrorCode, ErrorCategory.InvalidOperation, ProviderName));
17: }
18: catch (Exception ex1)
20: ThrowTerminatingError(new ErrorRecord(ex1, "", ErrorCategory.InvalidResult, ProviderName));
21: }
This entire method boils down to two lines (10 and 11) - the rest is diagnostics and error handling. Note that we have to catch the RfidClientException and wrap the RemoteErrorMessage, otherwise the only feedback to the user is "Remote method failed" - an instance of absolutely correct and singularly useless feedback.
7. Now that the cmdlet has been created (sans documentation - we'll get to that in a minute), it's time to see the fruits of our labours. This cmdlet is executed against a base install of BizTalk RFID 2009 with the LLRP provider registered. Press F5 to start a debuggable instance of PowerShell, and dump out the basic provider information:
PS C:\files\BizTalkRFID.PowerShell\bin\Debug> Get-RfidProviderStatus Name : LLRP ProviderFaults : {} LastFaultType : None LastFaultTime : 1/1/0001 12:00:00 AM ProviderState : Registered
Exciting stuff, eh? :). The real "wow" factor here isn't being able to dump out this basic list - could do that with rfidclientconsole. The exciting part is now this information can leverage all of the power and utility of PowerShell scripting to do things, build reports, drive automation, etc. Expanding the idea a bit:
PS C:\Files> Get-RfidProviderStatus | format-table Name,ProviderState -autosize Name ProviderState ---- ------------- LLRP Registered
Creating a simple table of available and registered providers.
1: PS C:\Files> Get-RfidProviderStatus | where-object { $_.ProviderState -eq 'Regis
2: tered' }
3:
4:
5: Name : LLRP
6: ProviderFaults : {}
7: LastFaultType : None
8: LastFaultTime : 1/1/0001 12:00:00 AM
9: ProviderState : Registered
Now we're starting to do fun things - with this command we filtered out registered provider names. Further on in this series when we create cmdlets such as Start-RfidProvider, we could write simple scripts that automatically started all Registered providers with something as simple as
Get-RfidProviderStatus | ? {$_.ProviderState -eq 'Registered' } | Select-Object Name | Start-RfidProvider
The next cmdlet will be retrieving the metadata from a provider, or set of providers. This cmdlet is nearly identical to the previous, the only difference being the cmdlet name, Cmdlet() attribute definition, and implementation of ProcessRecord.
1: [Cmdlet(VerbsCommon.Get, "RfidProviderMetadata", SupportsShouldProcess = false)]
2: public class MyCmdlet1 : Cmdlet
3: {
4: ...
5:
6: protected override void ProcessRecord()
7: {
8: foreach (string name in ProviderName)
9: {
10: try
11: {
12: WriteVerbose("Retrieving provider metadata..");
13: ProviderMetadata meta = provProxy.GetProviderMetadata(name);
14: WriteObject(meta);
15: }
16: catch (RfidClientException ex0)
17: {
18: ApplicationException ex_app = new ApplicationException(ex0.RemoteErrorMessage, ex0);
19: WriteError(new ErrorRecord(ex_app, ex0.RemoteErrorCode, ErrorCategory.InvalidOperation, name));
20: }
21: catch (Exception ex1)
22: {
23: ThrowTerminatingError(new ErrorRecord(ex1, "", ErrorCategory.InvalidResult, name));
24: }
25: }
26: }
Compile and run the updated project. From the PowerShell window you should now be able to execute the Get-RfidProviderMetadata cmdlet, as per:
ug> Get-RfidProviderMetadata LLRP -verbose VERBOSE: Retrieving provider metadata.. ProviderInformation : <providerInformation><id>Microsoft BizTalk RFI D LLRP Provider</id><description>Provider for LLRP devices</description><version>3.7.0.0</ve rsion></providerInformation> ProviderCapabilities : {The provider supports TCP/IP transport., The provider supports raising a defunct event., Th e provider supports device discovery., The pro vider supports triggering of device discovery. } ProviderPropertyMetadata : {[Connection:Port], [General:LLRP Version], [M anagement:LLRP Message timeout], [Management:T CP KeepAlive Time]...} VendorExtensionsEntityMetadata : {[HoppingEvent:DSPI management event], [Reader ExceptionEvent:DSPI management event], [RFSurv eyEvent:DSPI management event], [ConnectionAtt emptEvent:DSPI management event]...} DevicePropertyMetadata : {[LLRP General Capabilities:Antenna Sensitivit y Maximum Index], [LLRP General Capabilities:A ntenna Sensitivity Minimum Index], [LLRP Gener al Capabilities:Can Set Antenna Properties], [ LLRP General Capabilities:Has UTC Clock Capabi lity]...}
Not very exciting, either. Or is it? Remember that PowerShell uses the default formater defined by the underlying .NET type - in this case output as XML. Those aren't text strings, but fully fledged objects that can be manipulated. Like this:
PS C:\Files> $meta = Get-RfidProviderMetadata LLRP PS C:\Files> $meta.ProviderCapabilities Value : 4 Description : The provider supports TCP/IP transport. IsDiscoveryRelated : False IsEventRelated : False IsTransportRelated : True Value : 3 Description : The provider supports raising a defunct event. IsDiscoveryRelated : False IsEventRelated : True IsTransportRelated : False Value : 1 Description : The provider supports device discovery. IsDiscoveryRelated : True IsEventRelated : False IsTransportRelated : False Value : 2 Description : The provider supports triggering of device discovery. IsDiscoveryRelated : True IsEventRelated : False IsTransportRelated : False
Displaying the list of capabilities for the LLRP provider.
PS C:\Files> $meta.DevicePropertyMetadata.Keys | sort GroupName GroupName PropertyName --------- ------------ General Regulatory region General Name General Firmware version General Vendor...
Listing out the provider properties (full list truncated for space reasons).
PS C:\Files> $meta.DevicePropertyMetadata.Keys | sort GroupName | format-table -autosize | select-object -first 10 GroupName PropertyName --------- ------------ General Regulatory region General Name General Firmware version General Vendor LLRP Access Report Spec Trigger LLRP Antenna Configuration Receiver Sensitivity Index LLRP Antenna Configuration Transmit Power Index LLRP Antenna Configuration Hop Table Id
Listing the first 10 provider properties, sorted by GroupName, with automatic sizing in the table formatting.
Now to dig a little deeper into provider properties. The GetProviderProperties() method of the ProviderManagerProxy() returns the non-default (i.e. changed) values from the provider. The GetProviderMetadata() returns the metadata for said properties, including the defaults. Useful information, but in two separate buckets. Let's write a cmdlet that returns a unified view of the properties using a custom PSObject (i.e. leveraging PowerShell's awesome adaptive type system).
1. This cmdlet is nearly identical to the previous, the only difference being the cmdlet name, Cmdlet() attribute definition, and implementation of ProcessRecord. The definition of the class and Cmdlet attribute is:
1: [Cmdlet(VerbsCommon.Get, "RfidProviderProperty", SupportsShouldProcess = true)]
2: public class GetRfidProviderPropertiesCmdlet : Cmdlet
2. The implementation of ProcessRecord is a little trickier, and requires some explanation.
3: foreach (string name in ProviderName)
5: try
6: {
7: WriteVerbose("Retrieving provider metadata..");
8: ProviderMetadata meta = provProxy.GetProviderMetadata(name);
10: WriteVerbose("Retrieving provider properties..");
11: PropertyProfile prof = provProxy.GetProperties(name);
13: foreach (PropertyKey k in meta.ProviderPropertyMetadata.Keys)
15: PSObject obj = new PSObject(meta.ProviderPropertyMetadata[k]);
16: obj.Properties.Add(new PSNoteProperty("Group", k.GroupName));
17: obj.Properties.Add(new PSNoteProperty("Name", k.PropertyName));
18: // Modified value
19: if (prof.Keys.Contains(k))
20: {
21: PSNoteProperty n = new PSNoteProperty("Value", prof[k]);
22: obj.Properties.Add(n);
23:
24: PSNoteProperty o = new PSNoteProperty("Default", false);
25: obj.Properties.Add(o);
27: // Default value
28: else
29: {
30: PSNoteProperty n = new PSNoteProperty("Value",
31: meta.ProviderPropertyMetadata[k].DefaultValue);
32: obj.Properties.Add(n);
33:
34: PSNoteProperty o = new PSNoteProperty("Default", true);
35: obj.Properties.Add(o);
36: }
37: WriteObject(obj);
38: }
39: }
40: catch (RfidClientException ex0)
41: {
42: ApplicationException ex_app = new ApplicationException(ex0.RemoteErrorMessage, ex0);
43: WriteError(new ErrorRecord(ex_app, ex0.RemoteErrorCode, ErrorCategory.InvalidOperation, name));
44: }
45: catch (Exception ex1)
46: {
47: ThrowTerminatingError(new ErrorRecord(ex1, "", ErrorCategory.InvalidResult, name));
48: }
49: }
50: }
Line 3 - Since we can receive multiple provider names, we'll iterate over each.
Line 7-11: In order to aggregate the property information, we need to retrieve both the metadata and property profile.
Line 13: As the metadata has the "master" list of all properties, we use this as the baseline for enumeration.
Line 15-17: Here is the PowerShell magic. We're going to create a PowerShell object (PSObject) that wraps the native metadata object, and decorate it with some note properties. In this case the GroupName and the property name.
Line 19-25: If the property profile contains the value, then it's a non-default value. We add two note properties, one with the modified value, the other with a flag indicating its non-default status.
Line 30-35: If the property profile does not contain the value, then it's a default value, which we grab from the metadata. We add two note properties, one with the modified value, the other with a flag indicating its default status.
Line 40-47: The usual error handling.
With this simple bit of code we can now do some interesting automation (well, for now we can play with data - once the Set-RfidProviderProperty cmdlets are written in future posts we can have more fun).
ug> Get-RfidProviderProperty LLRP | format-table Group Name Value Default IsInitO Type Descrip LowerRa HigherR ValueEx nly tion nge ange pressio n ----- ---- ----- ------- ------- ---- ------- ------- ------- ------- Conn... Port 5084 True True Syst... Prov... 1 65535 General LLRP... 1.0.1 True False Syst... Indi... ...+308 ...+308 Mana... LLRP... 45000 True False Syst... Time... 10000 ...3647 Mana... TCP ... 60000 True False Syst... Time... 30000 ...3647 Conn... Devi... 60 True True Syst... Inte... 1 ...3647 Disc... Matc... 10 True False Syst... Indi... 1 ...3647
Retrieving all of the provider properties and their current values.
ug> Get-RfidProviderProperty Contoso | format-table Name,Value,Default -autosize Name Value Default ---- ----- ------- Init_NonEditable Rfid True Name Contoso True Description Sample Microsoft BizTalk RFID Provider True DevelopedBy Microsoft BizTalk RFID Team True Year Developed 2006 True Integer_Editable 100 True bool_Editable True True DiscoveryPort 9876 True HostDS False True XML False True
Having a look at the Contoso provider's properties.
PS C:\files\projects\Microsoft.Rfid.PowerShell\Microsoft.Rfid.PowerShell\bin\Debug> Get-RfidProviderProperty Contoso | ? {$_.Type.FullName -eq 'System.String' } | format-table Name,Value -autosize Name Value ---- ----- Init_NonEditable Rfid Name Contoso Description Sample Microsoft BizTalk RFID Provider DevelopedBy Microsoft BizTalk RFID Team
Get a list of all of the string type properties.
Most of this article was written while trying to create this one cmdlet, for automating log level configuration. This can be a somewhat non-intuitive exercise (or at least it was for me :), so a quick walkthrough of the steps involved may be useful. The log level appears on the Initialization Parameters of the Properties page of a provider in the RFID Manager. This may lead one to assume that the logging level is a property of the provider. One would be flat out wrong :)
The logging level is an aspect of the RFID Server Configuration. Let's use the rfidclientconsole to dump the server configuration and have a look:
1: C:\>rfidclientconsole GetServerConfiguration test.xml
2: C:\>type test.xml
4: <?xml version="1.0" encoding="utf-16"?>
5: <RfidServerConfiguration xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Microsoft.SensorServices.Rfid.Management">
6: <clusterNetworkName i:nil="true" />
7: <rfidServerBootstrapConfiguration>
8: <eventLoggingPolicyForExceptions>
9: <logNonRfidServerExceptions>true</logNonRfidServerExceptions>
10: <minimumExceptionSeverityForLogging>Fatal</minimumExceptionSeverityForLogging>
11: </eventLoggingPolicyForExceptions>
12: <log>
13: <component>
14: <ComponentLogLevelType>
15: <level>Info</level>
16: <name>MSBizTalkRFID</name>
17: </ComponentLogLevelType>
18: <ComponentLogLevelType>
19: <level>Info</level>
20: <name>ProcessManager</name>
21: </ComponentLogLevelType>
22: <ComponentLogLevelType>
23: <level>Info</level>
24: <name>DeviceManager</name>
25: </ComponentLogLevelType>
26: <ComponentLogLevelType>
27: <level>Info</level>
28: <name>Device</name>
29: </ComponentLogLevelType>
30: <ComponentLogLevelType>
31: <level>Info</level>
32: <name>FixedTimerQ</name>
33: </ComponentLogLevelType>
34: <ComponentLogLevelType>
35: <level>Info</level>
36: <name>Common</name>
37: </ComponentLogLevelType>
38: <ComponentLogLevelType>
39: <level>Info</level>
40: <name>SecurityManager</name>
41: </ComponentLogLevelType>
42: <ComponentLogLevelType>
43: <level>Info</level>
44: <name>ProviderManager</name>
45: </ComponentLogLevelType>
46: <ComponentLogLevelType>
47: <level>Info</level>
48: <name>ComponentManager</name>
49: </ComponentLogLevelType>
50: <ComponentLogLevelType>
51: <level>Info</level>
52: <name>ConnectorServices</name>
53: </ComponentLogLevelType>
54: <ComponentLogLevelType>
55: <level>Info</level>
56: <name>RfidWebService</name>
57: </ComponentLogLevelType>
58: <ComponentLogLevelType>
59: <level>Error</level>
60: <name>Tracking</name>
61: </ComponentLogLevelType>
62: </component>
63: <dateTimeFormat i:nil="true" />
64: <defaultLogLevel>Info</defaultLogLevel>
65: <logFile>logs\RfidServices.log</logFile>
66: </log>
67: <rfidStore>
68: <connectionString>Persist Security Info=False;database=RFIDSTORE;Integrated Security=SSPI; server=MASIMMS-DESKTOP</connectionString>
69: </rfidStore>
70: <wsConfiguration>
71: <wSPort>0</wSPort>
72: <wSPortSpecified>false</wSPortSpecified>
73: </wsConfiguration>
74: </rfidServerBootstrapConfiguration>
75: <rfidServerRuntimeConfiguration>
76: <deviceManagerConfiguration>
77: <autoApplyNonPersistentProperties>true</autoApplyNonPersistentProperties>
78: <deviceCommandResponseTimeoutMilliseconds>180000</deviceCommandResponseTimeoutMilliseconds>
79: <deviceConnectionCheckTimeMilliseconds>60000</deviceConnectionCheckTimeMilliseconds>
80: <deviceConnectionFailedThreshold>10</deviceConnectionFailedThreshold>
81: <deviceConnectionRetryTimeMilliseconds>60000</deviceConnectionRetryTimeMilliseconds>
82: <maxTagPrintedEvent>50</maxTagPrintedEvent>
83: <stampNotificationEventWithID>false</stampNotificationEventWithID>
84: </deviceManagerConfiguration>
85: <exposeStackTrace>false</exposeStackTrace>
86: <hostingConfiguration>
87: <iisHost>localhost</iisHost>
88: <iisPort>80</iisPort>
89: <iisTimeOutSeconds>60</iisTimeOutSeconds>
90: <iisWebsiteId>1</iisWebsiteId>
91: </hostingConfiguration>
92: <logConfiguration>
93: <currentBackupIndex>0</currentBackupIndex>
94: <fileCheckFrequency>25</fileCheckFrequency>
95: <fileCount>2</fileCount>
96: <fileSize>10</fileSize>
97: <maxAllowedDuplicates>3</maxAllowedDuplicates>
98: <spamControlTimePeriodInMinutes>10</spamControlTimePeriodInMinutes>
99: </logConfiguration>
100: <processManagerConfiguration />
101: <providerManagerConfiguration>
102: <delegateThreadTimeoutMilliseconds>60000</delegateThreadTimeoutMilliseconds>
103: <providerSideBySideLoadAllowed>false</providerSideBySideLoadAllowed>
104: </providerManagerConfiguration>
105: <wSConfiguration>
106: <shouldAuditSuccess>false</shouldAuditSuccess>
107: </wSConfiguration>
108: </rfidServerRuntimeConfiguration>
109: </RfidServerConfiguration>
Wow. That's a lot of stuff. The interesting items are the logging components. These define the individual logging level for each component in the system, both internal system components and the "user" components such as providers and processes.
Note that the LLRP provider does NOT appear in this list. This is due to the INHERIT LOG LEVEL checkbox being set in the RFID Manager. If a user component is set to inherit a logging setting, it will not have an entry in the RFID Server Configuration data set. This comes into play in our implementation of the Set-RfidLoggingLevel command.
The ServerManagerProxy exposes a very chunky interface, meaning that we have to retrieve the RFID server configuration, make changes to that configuration, then dump the configuration back in order to effect any changes.
1: [Cmdlet(VerbsCommon.Set, "RfidLogLevel", SupportsShouldProcess = true)]
2: public class SetRfidLogLevelCmdlet : Cmdlet
2. The parameter set is a little different, consisting of the Log Level, followed by the component names with an optional Server parameter.
2: Mandatory = true,
4: HelpMessage = "Logging Level")]
6: public ConfigLogLevel Level
8: get;
9: set;
10: }
11:
12: [Parameter(Position = 1,
13: Mandatory = true,
14: ValueFromPipelineByPropertyName = true,
15: HelpMessage = "The name (or names) of the target components (providers and processes")]
16: [ValidateNotNullOrEmpty]
17: [Alias("name")]
18: public string[] ComponentName
24: [Parameter(Position = 2,
25: Mandatory = false,
26: ValueFromPipelineByPropertyName = true,
27: HelpMessage = "The name of the target BizTalk RFID server")]
28: [ValidateNotNullOrEmpty]
29: public string Server
30: {
31: get;
32: set;
33: }
3. The initialization code is also a little different. In order to perform parameter validation we need to have the list of user components (providers and processes), and will thus need the proxy objects to access these in addition to the ServerManagerProxy.
1: private ServerManagerProxy srvProxy;
2: private ProviderManagerProxy provProxy;
3: private ProcessManagerProxy procProxy;
5: protected override void BeginProcessing()
7: if (String.IsNullOrEmpty(this.Server))
9: srvProxy = new ServerManagerProxy();
10: provProxy = new ProviderManagerProxy();
11: procProxy = new ProcessManagerProxy();
13: else
15: srvProxy = new ServerManagerProxy(this.Server);
16: provProxy = new ProviderManagerProxy(this.Server);
17: procProxy = new ProcessManagerProxy(this.Server);
18: }
19: }
4. Now the good stuff. Actually implementing the changes.
5: // Get the server configuration, which contains the logging level information in the
6: // bootstrap (i.e. startup) settings
7: WriteVerbose("Retrieving server configuration");
8: RfidServerConfiguration config = srvProxy.GetServerConfiguration();
10: // Get the list of provider and process names - these are the only valid components
11: WriteVerbose("Retrieving provider list");
12: ProviderStatus[] provStatus = provProxy.GetProviderStatus(null);
13: List<string> providerNames = new List<string>();
14: foreach (ProviderStatus s in provStatus)
15: providerNames.Add(s.Name);
16:
17: WriteVerbose("Retrieving process list");
18: List<string> procNames = new List<string>(procProxy.GetAllProcesses());
19:
20: // Perform parameter validation on the list of input components
21: List<string> validComponents = new List<string>();
22: foreach (string name in this.ComponentName)
23: {
24: if (procNames.Contains(name) || providerNames.Contains(name))
25: {
26: WriteVerbose("Component " + name + " is a valid logging component");
27: validComponents.Add(name);
28: }
29: else
31: WriteWarning("Component " + name + " is not a process or provider name");
32: }
34:
35: foreach (ComponentLogLevelType n in config.RfidServerBootstrapConfiguration.log.component)
36: {
37: if (validComponents.Contains(n.name))
38: {
39: WriteVerbose("Changing log level of component " + n.name + " to " + Level.ToString());
40: n.level = this.Level;
41: validComponents.Remove(n.name);
42: }
43: }
44:
45: // Check for "default" logging levels
46: List<ComponentLogLevelType> vals = new List<ComponentLogLevelType>(
47: config.RfidServerBootstrapConfiguration.log.component);
48:
49: foreach (string name in validComponents)
50: {
51: WriteVerbose("Setting log level of component " + name + " to non-default value " + Level.ToString());
52: ComponentLogLevelType t = new ComponentLogLevelType();
53: t.name = name;
54: t.level = Level;
55: vals.Add(t);
56: }
57: config.RfidServerBootstrapConfiguration.log.component = vals.ToArray();
58:
59: WriteVerbose("Updating Server..");
60: srvProxy.SetServerConfiguration(config);
61:
62: }
63: catch (RfidClientException ex0)
64: {
65: ApplicationException ex_app = new ApplicationException(ex0.RemoteErrorMessage, ex0);
66: ThrowTerminatingError(new ErrorRecord(ex_app, ex0.RemoteErrorCode, ErrorCategory.InvalidOperation, this.Server));
67: }
68: }
69: }
adfasdfasdf
All of this code (well, it's not a huge amount), but we get a very straightforward logging configuration experience:
ug> Set-RfidLogLevel Verbose LLRP -verbose VERBOSE: Retrieving server configuration VERBOSE: Retrieving provider list VERBOSE: Retrieving process list VERBOSE: Component LLRP is a valid logging component VERBOSE: Changing log level of component LLRP to Verbose VERBOSE: Updating Server..
Once we have the opportunity to implement more of the Get-Rfid* cmdlets, this method can be used to do some interesting things. However, since we already have a way to retrieve a list of the provider names:
ug> Get-RfidProviderStatus | select-object Name | Set-RfidLogLevel Verbose -verbose VERBOSE: Retrieving server configuration VERBOSE: Retrieving provider list VERBOSE: Retrieving process list VERBOSE: Component LLRP is a valid logging component VERBOSE: Changing log level of component LLRP to Verbose VERBOSE: Updating Server.. VERBOSE: Retrieving server configuration VERBOSE: Retrieving provider list VERBOSE: Retrieving process list VERBOSE: Component Contoso is a valid logging component VERBOSE: Changing log level of component Contoso to Verbose VERBOSE: Updating Server..
PowerShell script to set all of the Provider log levels to Verbose.
Note: because of the use of ProcessRecord the log levels are being changed sequentially. A more efficient way of doing it would be to aggregate the component names in ProcessRecord and actually update the server in EndProcessing.
PingBack from http://www.clickandsolve.com/?p=24463