NIC Order in PowerShell - powershell

I have a script where it will provide the NIC binding order like below. But is there anyway so that I can write a condition if binding order is vEthernet*,storage then
Add-Content $report "<td bgcolor= 'Aquamarine' height='25' align=center><B>$ServicesResult1</B></td>"
else
Add-Content $report "<td bgcolor= 'Yellow' height='25' align=center><B>$ServicesResult1</B></td>"
$result1 = Invoke-Command -ComputerName slcae212 -ScriptBlock {
Function Get-BindOrder {
$Binding = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage").Bind
$Return = New-Object PSobject
$BindingOrder = #()
foreach ($Bind in $Binding) {
$DeviceId = $Bind.Split("\")[2]
$Adapter = (Get-WmiObject Win32_Networkadapter | Where {$_.GUID -eq $DeviceId }).NetConnectionId
$BindingOrder += $Adapter
}
$BindingOrder
} #EndFunction
CLS
Get-BindOrder
}
$adapteresult1= $result1 -join ","
Output:
vEthernet (10.211.21.0_20),,storage,Ethernet 5,Ethernet 4,Ethernet 2,Ethernet 6,,

Im not sure where in your you need it but you can use a regex to check that:
vEthernet[^,]+?,storage
Now you can use that in an if statement using the -match operator:
if ($yourBinding -match 'vEthernet[^,]+?,,storage')
{
# do something
}
else
{
# do something else
}

With all respect, I don't think that you are on the correct way with programming this. I presume that you eventually want to reorder the "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage").Bind and put that back in the registry. (Years ago I have had similar request and at created a VBScript for that.)
In your script, your currently trying to deal with the adapter names to redefine the order of the original bindingorder but the relation between the $DeviceID and the $Adapter name is completely lost in you current approach.
Instead of doing string manipulation it is better, faster and more native to PowerShell to work with objects in the form of an array or in this case even a HashTable or 'PSCustomObject' where you keep a related between the $DeviceID and the $Adapter name. I would like to point out here that you could possible have multiple vEthernet adpaters and that some $adapter names are apparently empty (there is nothing between two commas ...,,...), but AFAIK that doesn't imply that you just can drop the $DeviceID (without adapter name) from the binding order...
I think there is a good example for your request written here:
https://seawin.org/2016/06/04/setting-binding-and-route-registry-entries/
Notes:
Your binding order could potential change on the fly e.g. if a user create a VPN connection or starts a VM, this probably means that you can not just run your fix at startup or logon but depending on the actual problem, you might have to fix it as it happens by setting a NotificationQuery event on the specific HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage registry key.
Changing the binding order (on the fly) has a significant impact on the Operating System processes, besides that you CPU will raise, network connection are being reset and could be unavailable for a while. Therefor I advice you to check/flag whether the binding order really changed (where required) and only rewrite it when necessarily.
I doubt whether the known issues related to the binding order are the same for every Operating Systems. Meaning, if you are going to deploy this to multiple OS versions, I would investigate the actual problem you dealing which, also applies to the concerned Operating System.

Related

How to use Remove-LocalGroupMember to remove from a server?

I have the following script that is supposed to remove members from a server:
$ssasInstance = ""
$accountName= ""
Import-Module SqlServer
[Microsoft.AnalysisServices.Server]$SSASserver = New-Object ([Microsoft.AnalysisServices.Server])
$SSASserver.Connect($ssasInstance)
$role= $SSASserver.Roles["Administrators"]
$role.Members.Remove($accountName)
$role.Update()
The problem is for some reason Remove() is not really working, no errors generated, but it doesnt remove the user.
I tested the script by instead adding a user, $role.Members.Add($accountName) and this works great! so i know that it must be a bug with the remove() method, and the only option I have is to use Remove-LocalGroupMember
I tried just using it like this:
$ssasInstance = ""
$accountName= ""
Import-Module SqlServer
[Microsoft.AnalysisServices.Server]$SSASserver = New-Object ([Microsoft.AnalysisServices.Server])
$SSASserver.Connect($ssasInstance)
$role= $SSASserver.Roles["Administrators"]
Remove-LocalGroupMember -Group "Administrators" -Member "$accountName"
$role.Update()
but that doesnt work either...although i think its because it doesnt know exactly where its removing from...
I tried this too, but to no avail:
Remove-LocalGroupMember -Group "$role" -Member "$accountName"
So how can i integrate this module into my script?
This is an unfortunate confluence of circumstances: when you do
$role.Members.Add("member")
This works because, under water, the string "member" is implicitly converted by PowerShell to a RoleMember with a Name of member and an empty Sid. All fine. However, if you then do
$role.Members.Remove("member")
Nothing happens, because you will create a new RoleMember instance, and since RoleMember has no implementation of .Equals() (a fairly bizarre oversight), different instances will never be considered the same.
This means you can only remove members by getting the actual instance in the collection (or by index, I suppose):
$member = $role.Members.Where{$_.Name -eq "member"} | Select -First 1
$role.Members.Remove($member)
Note that you will not get an error if there is no such member (because Remove allows $null, again in a rather bizarre oversight), so you may want to check for $member -eq $null if you want to verify that.
Definitely do not use Remove-LocalGroupMember -- that cmdlet is part of a completely different module and removes members from local Windows groups, not SSAS roles.

Why is Enumeration Name property not working?

I have a script that i want to display the connection strings of a database
Import-Module SqlServer
$AS = New-Object Microsoft.AnalysisServices.Server
$AS.connect("server1")
Now if i use the FindByName() property
$db = $AS.Databases.FindByName("database1")
$db.DataSources[0].ConnectionString
I get back the connection string successfully
however if i use Enumerator
foreach ($db in $AS.Databases.GetEnumerator())
{ $dbName = $db.Name
$dbName
$dbName.DataSources[0].ConnectionString
}
I get back the database name along with error/exception (because it couldnt get connection string for some reason):
database1
Cannot index into a null array.
database2
Cannot index into a null array.
I tried the following also:
$database1 = "database1"
$database1.DataSources[0].ConnectionString
and i also get back the same exception
So why is it that only FindByName works?
for additional info, this is what GetEnumerator lists:
$AS.Databases.GetEnumerator()
but also $AS.Databases
outputs the same thing...so whats even the point of the enumerator?
gm -i $AS.Databases
gm -i $AS.Databases..GetEnumerator()
Part of what you're seeing is PowerShell's handling of (some) enumerables. Many (most?) are unrolled by PowerShell automatically, so the call to .GetEnumerator() isn't needed.
That's what's happening in your last example, looking at $AS.Databases vs $AS.Databases.GetEnumerator(). But it's only because you sent it out to the pipeline in that case; it's the display process that did the unrolling (in both cases).
If you did gm -i $AS.Databases vs gm -i $AS.Databases.GetEnumerator() you're going to see the difference; same if you assigned each of those to a variable and tried to call methods on them.
But back to using foreach it should again be redundant: foreach ($db in $AS.Databases) should work the same as foreach ($db in $AS.Databases.GetEnumerator()) but I don't have this type in my env right now to test that.
So back to the issue at hand inside the foreach, I suggest you start checking types again. Compare:
$db = $Analysis_Server.Databases.FindByName("database1")
gm -i $db
to
foreach ($db in $AS.Databases.GetEnumerator())
{
gm -i $db
break
}
You might find the types aren't what you think.
This is especially true because you're using dot . notation, because PowerShell has another array shortcut built-in since version 3, whereby you can use . on an array of types, to return an array of the .Property of each item. For example:
$p = Get-Process chrome # choose your own adventure
$p.Count
$p[0].Name
$p.Name
So a property you thought you were accessing on a single object, may have been on an array of objects, and may have been returning an array (or a single object), and handing that in the foreach may have returned a different quantity, or something, resulting in your attempt to index into what used to be an array, no longer work.
But again it's speculation on my part because I don't have those objects. Hopefully this helps you dig deeper into it though.
PowerShell does its own enumerating.
This done the trick!
foreach ($db in $AS.Databases){
Write-Hst $db.Name -Fore green
$db.DataSources | ForEach-Object{$_.ConnectionString}
}

Export-Csv MIM FIM PowerShell Issue

I was asked to retrieve a .csv list with all users that registered to the FIM portal. I did some searching until I stumbled accross this script:
set-variable -name URI -value "http://localhost:5725/resourcemanagementservice' " -option constant
set-variable -name CSV -value "RegistredResetPassUsers.csv" -option constant
clear
If(#(Get-PSSnapin | Where-Object {$_.Name -eq "FIMAutomation"} ).count -eq 0) {Add-PSSnapin FIMAutomation}
$WFDFilter = "/WorkflowDefinition[DisplayName='Password Reset AuthN Workflow']"
$curObjectWFD = export-fimconfig -uri $URI –onlyBaseResources -customconfig ($WFDFilter) -ErrorVariable Err -ErrorAction SilentlyContinue
$WFDObjectID = (($curObjectWFD.ResourceManagementObject.ResourceManagementAttributes | Where-Object {$_.AttributeName -eq "ObjectID"}).value).split(":")[2]
$Filter = "/Person[AuthNWFRegistered = '$WFDObjectID']"
$curObject = export-fimconfig -uri $URI –onlyBaseResources -customconfig ($Filter) -ErrorVariable Err -ErrorAction SilentlyContinue
[array]$users = $null
foreach($Object in $curObject)
{
$ResetPass = New-Object PSObject
$UserDisplayName = (($Object.ResourceManagementObject.ResourceManagementAttributes | Where-Object {$_.AttributeName -eq "DisplayName"}).Value)
$ResetPass | Add-Member NoteProperty "DisplayName" $UserDisplayName
$Users += $ResetPass
}
$users | export-csv -path $CSV
The script works without errors except that the actual list that it exports only contains my display name. I've been trying to figure out why its not exporting the complete list of all users and only shows my name, but I haven't been able to figure it out so I was wondering if any one could help me shed some light into this issue.
Thanks again for any help you guys can provide!
No experience with this snapin/product, but seeing as the code fundamentally works (it returns your object) this could be a permissions issue. You may not be able to read the other user objects, so they're not being exposed to you.
If you can view them in a UI console of some kind, then check for separate permissions related to API actions, and ensure you have access that way.
Another course of action may be to run the code line by line and see what results you receive from each line, to make sure you get what you're expecting.
Try replacing:
[array]$users = $null
With:
$users = #()
This is likely due to permission setup.
By default you have a permissions to see your own attributes.
There is likely some Management Policy Rule setup so user accounts in a specific Set can read AuthNWFRegistered attribute of other users to support for troubleshooting and customer support.
You will need to use one of the options:
Add the account used for this script into the Set that delegates out this Read permission already
or
Create a separate MPR for this particular reporting (this is what I would recommend) that Grants permissions for a specific user account to read AuthNWFRegistered attribute.
Also make sure there is really only one Workflow that is associated with user registration. If there are multiple, you'd want to target Set with all register Workflows in your XPath filter instead of particular Workflow name.
On a separate note - while FIMAutomation is sometimes necessary snapin to use with standard tooling, for your custom work I strongly suggest to use Lithnet's LithnetRMA PowerShell module (https://github.com/lithnet/resourcemanagement-powershell).
You will be much more productive with it and most of the operations will be without boilerplate code FIMAutomation needs. This will be your code using LithnetRMA.
Set-ResourceManagementClient -BaseAddress 'http://localhost:5725/resourcemanagementservice'
$scope = Search-Resources -XPath "/Person[AuthNWFRegistered = /WorkflowDefinition[DisplayName='Password Reset AuthN Workflow']]" -ExpectedObjectType Person
$scope | select DisplayName | Export-Csv 'RegistredResetPassUsers.csv' -Encoding Unicode

Accuracy of root/CIMV2/Security/MicrosoftVolumeEncryption VS. manage-bde.exe?

I am trying to determine the accuracy of reporting from 2 seemingly difference sources (using powershell on Windows devices):
Method1
manage-bde.exe -computername $hostname -status
Returns something like 100% encrypted and partition size
Method 2
if($encryption_check_all = Get-WMIObject -ComputerName $hostname -Namespace "root/CIMV2/Security/MicrosoftVolumeEncryption" -query "SELECT * FROM Win32_EncryptableVolume WHERE DriveLetter='C:'" | Select-Object *){
$encryption_check = $encryption_check_all.ProtectionStatus
if ($encryption_check -eq "1"){$encryption_status = "Encrypted" ; $encryption_value = 200 }
if ($encryption_check -eq "0"){$encryption_status = "No Encryption Found" ; $encryption_value = 200 }
else{}
Returns a value of "1" or "0". 0 meaning partition not encrypted, partially encrypted, or keys in plain text. BOTH snippets "work" as far as the code goes, BUT they return conflicting results. Does anyone have experience or validation for either method? Im having a device return with method 1 as a "0" but bde.exe says it is 100% encrypted. Does this for sure mean that keys are present in plain text or is there other nuances im unaware of? Any clarity is greatly appreciated.
Also if anyone is aware of data source from bde.exe. Is this just an exe to regurgitate AD bitlocker key recovery? I believe the WMI namespace call actually checks on device on partition- more accurate? THANKS!

returning and referencing remote powershell variable results

I'm very new to powershell so looking some assistance. I am trying to run remote powershell script to check health of or VDI enviroment using Citrix Commandlets. (I am implementing the script on Microsoft orchestrator .Net Activity). So I have the following code:
#2012 VDI Desktop check
$vdims = "MyCitrixPowershellSDKServer"
function vdidesktopcheck
{
asnp Citrix*
$result = Get-BrokerDesktop -InMaintenanceMode $True -DesktopGroupName Unidesk
$result
}
$output = invoke-command -computer $vdims -scriptblock ${function:vdidesktopcheck}
$machinename = $output.machinename
$machinename
$state = $output.RegistrationState
$state
So when I use orchestrator to expose the variables $machinename, $state - I get the 'last' result from the involked Get-BrokerDesktop query. However Get-Brokerdesktop query may have multiple machines returned so I am hoping to be able to reference each of the machines that match the query output. Thats the basic requirement - what I am hoping to be able to do is further refine the basic Get-BrokerDesktop query to be able to count the number on machines output to say > 3 (ie more than 3 machines in MaintMode is unacceptable) and also check that the MachineName property is not equal to a particular value, ie the 3 test machine names in the environment which may be expected to be in MaintenanceMode.
Hope this makes sense, if not I'll try and elaborate. Any help much appreciated!!
One of the limitations of Orchestrator is that you can only pass strings across the data bus, and you need to pass an array of objects. You need to serialize the object array to a string. One way to do that is to convert the array to json, then use convertfrom-json when you get it back to get an object array to work with.
Don't have a SCORCH server handy to test with, so this isn't tested at all.
$vdims = "MyCitrixPowershellSDKServer"
function vdidesktopcheck
{
asnp Citrix*
$result = Get-BrokerDesktop -InMaintenanceMode $True -DesktopGroupName Unidesk
$result
}
$output = invoke-command -computer $vdims -scriptblock ${function:vdidesktopcheck} |
select machinename,RegistrationState | ConvertTo-Json
$Output