Reputation: 355
The following is stored in powershell
#Maintainer Note: The leftmost parameter must match the registry key name exactly e.g. 'DES 56'
#For more information please check https://support.microsoft.com/en-us/kb/245030
$bannedCiphersJSON = @"
{
"RC4 128/128":{
"IsPermitted":false,
"AffectedCiphers":[
"SSL_RSA_WITH_RC4_128_MD5",
"SSL_RSA_WITH_RC4_128_SHA",
"TLS_RSA_WITH_RC4_128_MD5",
"TLS_RSA_WITH_RC4_128_SHA"
]
},
"Triple DES 168":{
"IsPermitted":false,
"AffectedCiphers":[
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA" ,
"TLS_RSA_WITH_3DES_EDE_CBC_SHA" ,
"TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"
]
},
"RC4 56/128":{
"IsPermitted":false,
"AffectedCiphers":[
"TLS_RSA_EXPORT1024_WITH_RC4_56_SHA"
]
},
"DES 56":{
"IsPermitted":false,
"AffectedCiphers":[
"SSL_RSA_WITH_DES_CBC_SHA"
]
},
"RC4 40/128":{
"IsPermitted":false,
"AffectedCiphers":[
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"TLS_RSA_EXPORT_WITH_RC4_40_MD5"
]
},
"RC2 40/128":{
"IsPermitted":false,
"AffectedCiphers":[
"SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
"TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"
]
},
"MD5":{
"IsPermitted":false,
"AffectedCiphers":[
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_WITH_RC4_128_MD5",
"SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
"TLS_RSA_EXPORT_WITH_RC4_40_MD5",
"TLS_RSA_WITH_RC4_128_MD5",
"TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"
]
},
"SHA":{
"IsPermitted":false,
"AffectedCiphers":[
"SSL_RSA_WITH_RC4_128_SHA",
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT1024_WITH_RC4_56_SHA",
"TLS_RSA_WITH_RC4_128_SHA",
"TLS_RSA_WITH_DES_CBC_SHA",
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA",
"TLS_RSA_EXPORT1024_WITH_RC4_56_SHA"
]
}
}
"@
$bannedCiphers =$bannedCiphersJSON | ConvertFrom-Json
function Get-TLSProtocol{
For ($i=0; $i -lt $bannedCiphers.Count; $i++)
{
write-output $i
}
}
Get-TLSProtocol
When I run a Get-Member
against the object, each object seems to be a "note property". Because of this I think the array definition isn't correct. (my goal is to get a list of objects that I can use to inspect the registry.
PS C:\users\golden> $bannedCiphers | get-member
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
DES 56 NoteProperty System.Management.Automation.PSCustomObject DES 56=@{IsPermitted=False; AffectedCiphers=...
MD5 NoteProperty System.Management.Automation.PSCustomObject MD5=@{IsPermitted=False; AffectedCiphers=Sys...
RC2 40/128 NoteProperty System.Management.Automation.PSCustomObject RC2 40/128=@{IsPermitted=False; AffectedCiph...
RC4 128/128 NoteProperty System.Management.Automation.PSCustomObject RC4 128/128=@{IsPermitted=False; AffectedCip...
RC4 40/128 NoteProperty System.Management.Automation.PSCustomObject RC4 40/128=@{IsPermitted=False; AffectedCiph...
RC4 56/128 NoteProperty System.Management.Automation.PSCustomObject RC4 56/128=@{IsPermitted=False; AffectedCiph...
SHA NoteProperty System.Management.Automation.PSCustomObject SHA=@{IsPermitted=False; AffectedCiphers=Sys...
Triple DES 168 NoteProperty System.Management.Automation.PSCustomObject Triple DES 168=@{IsPermitted=False; Affected...
What is the correct way to define an object within powershell so that I can iterate over the top most layer?
Upvotes: 3
Views: 3994
Reputation: 355
Completed code, for your reference:
#Maintainer Note: The leftmost parameter must match the registry key name exactly e.g. 'DES 56'
#For more information please check https://support.microsoft.com/en-us/kb/245030
$bannedCiphersJSON = @"
[
{
"Name": "RC4 128/128",
"IsPermitted": false,
"AffectedCiphers": [
"SSL_RSA_WITH_RC4_128_MD5",
"SSL_RSA_WITH_RC4_128_SHA",
"TLS_RSA_WITH_RC4_128_MD5",
"TLS_RSA_WITH_RC4_128_SHA"
]
},
{
"Name": "Triple DES 168",
"IsPermitted": false,
"AffectedCiphers": [
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"
]
},
{
"Name": "RC4 56/128",
"IsPermitted": false,
"AffectedCiphers": [
"TLS_RSA_EXPORT1024_WITH_RC4_56_SHA"
]
},
{
"Name": "DES 56",
"IsPermitted": false,
"AffectedCiphers": [
"SSL_RSA_WITH_DES_CBC_SHA"
]
},
{
"Name": "RC4 40/128",
"IsPermitted": false,
"AffectedCiphers": [
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"TLS_RSA_EXPORT_WITH_RC4_40_MD5"
]
},
{
"Name": "RC2 40/128",
"IsPermitted": false,
"AffectedCiphers": [
"SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
"TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"
]
},
{
"Name": "MD5",
"IsPermitted": false,
"AffectedCiphers": [
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_WITH_RC4_128_MD5",
"SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
"TLS_RSA_EXPORT_WITH_RC4_40_MD5",
"TLS_RSA_WITH_RC4_128_MD5",
"TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"
]
},
{
"Name": "SHA",
"IsPermitted": false,
"AffectedCiphers": [
"SSL_RSA_WITH_RC4_128_SHA",
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT1024_WITH_RC4_56_SHA",
"TLS_RSA_WITH_RC4_128_SHA",
"TLS_RSA_WITH_DES_CBC_SHA",
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA",
"TLS_RSA_EXPORT1024_WITH_RC4_56_SHA"
]
}
]
"@
$bannedCiphers = $bannedCiphersJSON | ConvertFrom-Json
function Get-TLSCipher{
$TLSProtocolCollection = @()
$regIsEnabledResult
$regIsEnabledResultFriendly
$cipherError
For ($i=0; $i -lt $bannedCiphers.Name.Count; $i++)
{
$TLSProtocolResult = New-Object System.Object
$cipherError = ""
$clientPath = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\" + $bannedCiphers.Name[$i]
$canProceedWithKey = Test-Path -Path $clientPath
if ($canProceedWithKey)
{
$regIsEnabledResult = (Get-ItemProperty -path $clientPath).Enabled
if ($regIsEnabledResult -eq 0xffffffff -or $regIsEnabledResult -eq 0) {
$regIsEnabledResultFriendly = "false"
if($bannedCiphers.IsPermitted[$i] -eq "true")
{
$cipherError = "Should be enabled"
}
}
else
{
$regIsEnabledResultFriendly = "true"
if($bannedCiphers.IsPermitted[$i] -eq "false")
{
$cipherError = "Should be disabled"
}
}
}
else
{
$regIsEnabledResultFriendly = "OS Default"
$cipherError = "Unknown Status" #todo - consider adding a dictionary to determine this outcome
}
$TLSProtocolResult | Add-Member -MemberType NoteProperty -Name CipherShortName -Value $bannedCiphers.Name[$i]
$TLSProtocolResult | Add-Member -MemberType NoteProperty -Name IsEnabled -Value $regIsEnabledResultFriendly
$TLSProtocolResult | Add-Member -MemberType NoteProperty -Name Errors -Value $cipherError
$TLSProtocolCollection += $TLSProtocolResult
}
#Alert if there are cipher configurations on the machine that aren't considered in the script
$canProceedWithKey2 = Test-Path -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers"
if ($canProceedWithKey2)
{
$unexpectedKeys = Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers"
foreach ($crossCheck in $unexpectedKeys)
{
if (!$TLSProtocolCollection.CipherShortName.Contains($crossCheck.PSChildName))
{
$TLSProtocolResult = New-Object System.Object
$TLSProtocolResult | Add-Member -MemberType NoteProperty -Name CipherShortName -Value $crossCheck.PSChildName
$TLSProtocolResult | Add-Member -MemberType NoteProperty -Name IsEnabled -Value $crossCheck.Enabled
$TLSProtocolResult | Add-Member -MemberType NoteProperty -Name Errors -Value "Unexpected registry key. Update the 'bannedCiphersJSON' for this registry value"
$TLSProtocolCollection += $TLSProtocolResult
}
}
}
$TLSProtocolCollection
}
Get-TLSCipher
Upvotes: 0
Reputation: 19664
Just to add to the other answers based on your comments.. if you have control of the source of data (such as that JSON blob being hard-coded in your script), then just define an object instead of relying on conversion:
$obj = @{
'RC4 128/128' = @{
'IsPermitted' = $false
'AffectedCiphers' = @(
'SSL_RSA_WITH_RC4_128_MD5'
'SSL_RSA_WITH_RC4_128_SHA'
'TLS_RSA_WITH_RC4_128_MD5'
'TLS_RSA_WITH_RC4_128_SHA'
)
}
<# ... #>
}
Now you can access the object (in this case, a hashtable
) natively:
$obj.Keys
et cetera.
Upvotes: 0
Reputation: 7479
you have a PSCustomObject, not an array. that object has some arrays buried in the properties, tho. [grin] here's one way to get the list & the count ...
$AffectedCiphers = foreach ($PropName in $Test.PSObject.Properties.Name)
{
$Test.$PropName.AffectedCiphers
}
'There are {0} ciphers in the Banned Ciphers list.' -f $AffectedCiphers.Count
output:
There are 30 ciphers in the Banned Ciphers list.
what the above does:
.PSObject
property of all powershell objects .AffectedCiphers
property values (an array of values, in this case)$AffectedCiphers
$AffectedCiphers
hope that helps,
lee
Upvotes: 7
Reputation: 794
I think the only way to iterate over a CustomObject ist to get all the members, and then iterate over the members with a forEach. My solution is nearly the same like gms0ulmans solution, but a bit shorter.
($bannedCiphers | Get-Member -MemberType NoteProperty).ForEach({
$member = $_.Name
$value = $bannedCiphers.($_.Name)
Write-Host "Member: $member"
Write-Host "Is Permitted: " + $value.IsPermitted
Write-Host "Affected Ciphers + " ($value.AffectedCiphers -join ",")
})
Upvotes: 1
Reputation: 10019
This may not be the optimal solution but does demonstrate how to iterate over the json
contents. You do not need to know the Length
/Count
to achieve this.
Foreach($member in ($bannedCiphers | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name)){
Write-Host "Name: $member"
Write-Host "IsPermitted: $($bannedCiphers.$member.IsPermitted)"
Write-Host "Ciphers:$($bannedCiphers.$member.AffectedCiphers.Count)"
Foreach ($cipher in ($bannedCiphers.$member.AffectedCiphers)){
Write-Host " - $cipher"
}
Write-Host "`n"
}
Edit: Added $($bannedCiphers.$member.AffectedCiphers.Count)
Upvotes: 2