List SPN's Script - Write results to file issue - powershell

Good morning everyone.
I found this script on the InterWeb's which works phenominal. HOWEVER... No matter what I try, and where I put it, I can't seem to get it to do the results to an out-file.
What the hell am I doing wrong, and where does the variable need to go?
# Source / credit:
# https://social.technet.microsoft.com/wiki/contents/articles/18996.active-directory-powershell-script-to-list-all-spns-used.aspx
cls
$search = New-Object DirectoryServices.DirectorySearcher([ADSI]"")
$search.filter = "(servicePrincipalName=*)"
## You can use this to filter for OU's:
## $results = $search.Findall() | ?{ $_.path -like '*OU=whatever,DC=whatever,DC=whatever*' }
$results = $search.Findall()
foreach( $result in $results ) {
$userEntry = $result.GetDirectoryEntry()
Write-host "Object Name = " $userEntry.name -backgroundcolor "yellow" -foregroundcolor "black"
Write-host "DN = " $userEntry.distinguishedName
Write-host "Object Cat. = " $userEntry.objectCategory
Write-host "servicePrincipalNames"
$i=1
foreach( $SPN in $userEntry.servicePrincipalName ) {
Write-host "SPN ${i} =$SPN"
$i+=1
}
Write-host ""
}

Related

Scope/persistence of data issue

I'm not sure what to search for to solve this one. I have a scope/persistence of data issue, where a variable used to populate my data structure is over-writing other items in the data structure (ImageFileName). This is my code:
###Functions...first two are just for info
#method to get messages for mdb files
#dependency-Need to download accessDatabaseEngine(64 bit) redestributable: https://www.microsoft.com/en-us/download/details.aspx?id=54920
Function ProcessHelpMDB{
[cmdletbinding()]
Param ([string]$mdbLookupError, [string]$mdbFilePath, [string]$mdbDeviceSeries) #$mdbLookupError = error number, like 701. $mdbDeviceSeries is 1000
Process
{
#Write-Host "mdbLookupString: $mdbLookupString" -ForegroundColor Cyan
$adOpenStatic = 3
$adLockOptimistic = 3
#Write-Host "In ProcessMDB" -ForegroundColor darkRed
#$pathViewBase = 'C:\me\EndToEnd_view\' #View dir. Maybe param later
#$pathToMdb = Join-Path -Path $pathViewBase -ChildPath $mdbFileName
$deviceTable = $mdbDeviceSeries + "PP"
$mdbLookupError -Match '[0-9]*-([0-9]*)'
$errLookup = $Matches[1]
#Write-Host "dps" -ForegroundColor DarkMagenta
$selectQuery = “SELECT [$($deviceTable)].[HelpCode],
[$($deviceTable)].[ScreenNumber],
[$($deviceTable)].[TextID],
[$($deviceTable)].[PictureID]
FROM [$($deviceTable)]
WHERE
[$($deviceTable)].[HelpCode] = $($errLookup)"
$cn = new-object -comobject ADODB.Connection
$rs = new-object -comobject ADODB.Recordset
$cn.Open("Provider = Microsoft.ACE.OLEDB.16.0;Data Source = $mdbFilePath")
$rs.Open($selectQuery,
$cn, $adOpenStatic, $adLockOptimistic)
$i=0
$ret = [System.Collections.Generic.List[psobject]]::new()
if($rs.EOF)
{
Write-Host "$mdbLookupString not in $mdbFileName...record set returned emtpy for query"
}#if
else
{
while($rs.EOF -ne $True)
{
$result = [ordered]#{}
#$hash = #{}
foreach ($field in $rs.Fields)
{
$result[$field.name] = $field.Value
}#result
$newObject = [PSCustomObject]$result
$ret.Add($newObject) #
$rs.MoveNext()
} #while
}#else
Write-Host "retArr[0] $($ret[0])" #prints retArr[0] #{PictureID=HELP_...; TextID=HELP_...; HelpCode=9; ScreenNumber=1}
$i=0
foreach($row in $ret) #goes thru all rows
{
Write-Host "retArr[0] $($ret[$i,"TextID"])" #prints retArr[0] #{HelpCode=9; ScreenNumber=1; TextID=HELP_...; PictureID=HELP_...}
####
Write-Host "retArr[] $($row)" #prints retArr[] #{HelpCode=9; ScreenNumber=1; TextID=HELP_...; PictureID=HELP_7000_POWER_COVER_RIBBON}
Write-Host "retArr[0] $($row[$i])" #prints retArr[0] #{HelpCode=9; ScreenNumber=1; TextID=HELP_...; PictureID=HELP_...}
$i++
}
foreach($row in $ret.GetEnumerator()) #this is working for each row
{
Write-Host $row.TextID #prints HELP_...
Write-Host $row.'TextID' #prints HELP_...
}
$ret | ForEach-Object {
Write-Host TextID= $($_.TextID) #prints TextID= HELP_...
Write-Host TextID= $($_.'TextID') #prints TextID= HELP_...
} #
$cn.Close()
return $ret #Items queried from db ################################################# need to put them in excel file in order next
} #end Process
}# End of Function process mdb's
#This function gets mdb info out and returns English-US message found
Function ProcessK_MDB{
[cmdletbinding()]
Param ([string]$mdbLookupstring) #$mdbLookupString like HELP_...
Process
{
$adOpenStatic = 3
$adLockOptimistic = 3
$pathViewBase = 'C:\me\\EndToEnd_view\' #View dir. Maybe param later
$mdbFileNamePath = 'KAppText.mdb'
$pathToMdb = Join-Path -Path $pathViewBase -ChildPath $mdbFileNamePath
if(Test-Path $pathToMdb)
{
$selectQuery = “SELECT [Messages].[Message Description],
[Messages].[English - Us]
FROM [Messages]
WHERE [Messages].[Message Description] = '$($mdbLookupString)'”
$cn = new-object -comobject ADODB.Connection
$rs = new-object -comobject ADODB.Recordset
$cn.Open("Provider = Microsoft.ACE.OLEDB.16.0;Data Source = $pathToMdb")
$rs.Open($selectQuery,
$cn, $adOpenStatic, $adLockOptimistic)
if($rs.EOF) #empty
{
Write-Host "$mdbLookupString not in $mdbFileName...record set returned emtpy for query"
$ret = ""
}#if
else #got results
{
$returnArr = $rs.GetRows()
#$ret = $returnArr[0,1]
#$ret2 = $returnArr[1,1]
$ret = $returnArr[1,0] #has long text
#$ret4 = $returnArr[0,0] #has short text
#Write-Host $ret
}#else got results
$cn.Close()
} #testPath
else {
Write-Host "$pathToMdb does not exist"
}
return $ret #Message English-US for parameter/Message Description given
} #end Process
}# End of Function process mdb's
Function Get-ImageName{
[cmdletbinding()]
Param ([string]$imageName, [string]$fileNamePath)
Process
{
#find image file name to look for
[System.String] $pictureName = ""
if($imageName -Match "HELP")
{
#remove "HELP" part of file name
$($row.PictureID) -Match "HELP_(.*)" #get the part after HELP_
Write-Host $Matches[0]
Write-Host $Matches[1]
$pictureName = $Matches[1]
}
else {
$pictureName = $imageName
}
$imageFile2 = Get-ChildItem -Recurse -Path $ImageFullBasePath -Include #("*.bmp","*.jpg","*.png") | Where-Object {$_.Name -match "$($pictureName)"} #$imageFile | Select-String -Pattern '$($pictureName)' -AllMatches
Write-Host "ImageFile2: $($imageFile2)"
$imgFile = ""
foreach($imgFile in $imageFile2) #there may be more than one...just get last one...there are multiple telephone images
{
if($imgFile.Exists) #if($imageFile2.Exists)
{
#$image = [System.Drawing.Image]::FromFile($imgFile) #may not need this step
#need to figure out which is correct if there's multiple images
return $imgFile
}
else {
Write-Host "$($imgFile) does not exist"
return $null
}
} #foreach imageFile2
return $null
} #end Process
}# End of Function process mdb's
###main####
$resultHelp = ProcessHelpMDB -mdbLookupError $errCode -mdbFilePath $basePathFull -mdbDeviceSeries $deviceVer #######
$result = foreach($row in $resultHelp.GetEnumerator()) #this is working for each row
{
if($row -ne $True) #not sure why it adds true at the top
{
Write-Host $row.TextID #prints HELP_...
#lookup value from kapptext.mdb
Write-Host $($row.TextID) #prints nothing but looks ok in next function
$longText = ProcessK_MDB -mdbLookupstring $($row.TextID) #gives English-US message from device for parameter given
#insert images######################
#I can see that these are assigned correctly and returned from Function:
[System.Drawing.Image] $image = New-Object System.Drawing.Image #error...see Update2
[System.String] $imageNamePath = New-Object System.String #error...see Update2
[System.String] $imageNamePath = Get-ImageName -imageName $($row.PictureID) -fileNamePath $ImageFullBasePath
if($null -ne $imageNamePath)
{
$image = Get-Image -imageFileName $imageNamePath
}
else
{
Write-Host "Did not find an image file for $($row.PictureID) in $ImageFullBasePath"
}
#get the data ready to put in spreadsheet
New-Object psobject -Property $([ordered]#{
ScreenNumber = $($row.ScreenNumber)
KPMKey = $($row.TextID)
EnglishUS = $($longText)
PictureID = $($row.PictureID)
ImageFound = ""
ImageFileName = $($imageNamePath) ###???this is over-written...all same in $result after done with loop
})
} #if not true
} #foreach row $resultHelp
##note: $image gets inserted in the spreadsheet later, but since the names aren't showing correctly when use $results, I'm not sharing that part.
I can see after this runs for the 9 rows, that each ImageFileName is the same in $result. How do I do this so it maintains what is returned from the method? Right now I am trying New-Object, but it didn't fix the issue.
This is what $resultHelp looks like:
[0] $true (I'm not sure why it puts true at the top) [1]
#(HelpCode=9;ScreenNumber=1;TextID=HELP_...JA;PictureID=HELP_...RIB)
[2]
#(HelpCode=9;ScreenNumber=2;TextID=HELP_...ROLL;PictureID=HELP_...ROLL)
[3]
#(HelpCode=9;ScreenNumber=3;TextID=HELP_...EDGE;PictureID=HELP_...UT)
...
I am using Powershell 5.1 and VSCode.
Update:
I checked again, and in Get-ImageName, it's returning a file name like "Contact_Service"...bmp and it looks like it's getting put in the psObject ImageFileName...($imageNamePath), and the same thing for the other images found. When I look in the end, $result has all the same values for that ImageFileName. and the one that used to say "Contact_Service"..bmp is something else now, matching the other ones in $result.
Update2:
There are a couple errors:
New-Object : A constructor was not found. Cannot find an appropriate
constructor for type System.Drawing.Image
and
New-Object : A constructor was not found. Cannot find an appropriate
constructor for type System.String.
for where I tried dealing with the object over-write issue in the main code
Update3:
After I get the psobject in good shape, I put it in a spreadsheet with Export-Excel. I just wanted to give this info so you know why I'm putting it in the psobject like that:
$xlsx = $result | Export-Excel -Path $outFilePath -WorksheetName $errCode -Autosize -AutoFilter -FreezeTopRow -BoldTopRow -PassThru # -ClearSheet can't ClearSheet every time or it clears previous data
I figured it out.
the problem was that even though I was finding different $imageNamePaths for to assign to the Property as ImageFileName for each PictureID, and assigning those properties in the psobject in the foreach loop, I wound up with the same thing for each ImageFileName property (overwritten). This fixed it.
New-Object psobject -Property $([ordered]#{
ScreenNumber = $($row.ScreenNumber)
KPMKey = $($row.TextID)
EnglishUS = $($longText)
PictureID = $($row.PictureID)
ImageFound = ""
ImageFileName = "$($imageNamePath)" ####added double quotes
})
The double quotes let the different $imageNamePath values remain instead of being over-written. I'm not exactly sure why.
And thank you #Mathias, I will suppress output from my -Match to see if the $true is removed at the top of my data returned from the Function. :)

how can i write elegant ping with powershell

I create script for check available resources:
$servers = New-Object System.Collections.Generic.Dictionary"[String,String]"
$servers.Add("Server 1","127.0.0.1")
$servers.Add("Server 2","127.0.0.1")
$servers.Add("Server 3","127.0.0.1")
$virtuals = New-Object System.Collections.Generic.Dictionary"[String,String]"
$virtuals.Add("VM 1","127.0.0.1")
$virtuals.Add("VM 2","127.0.0.1")
$virtuals.Add("VM 3","127.0.0.1")
Write-Output("`n")
Write-Output("Check availiable servers")
foreach ($key in $servers.GetEnumerator()){
if ((Test-Connection $key.Value -Count 3 -Quiet)){
[pscustomobject]#{Server = $key.Key; Status = "Availiable"}
}else{
[pscustomobject]#{Server = $key.Key; Status = "Not availiable"}
}
}
Remove-Variable -Name [pscustomobject]
Write-Output("`n")
Write-Output("Check availiable virtuals")
Write-Output("`n")
foreach ($key in $virtuals.GetEnumerator()){
if ((Test-Connection $key.Value -Count 3 -Quiet)){
[pscustomobject]#{VM = $key.Key; Status = "Availiable"}
}else{
[pscustomobject]#{VM = $key.Key; Status = "Not availiable"}
}
}
If I change the title, then the output is in the following table without the first column. And I can't find how I can print the title in every new cycle? My ultimate goal is to have a header for each new loop and color-coded available and unavailable addresses.
If by 'elegant' you mean outputting a line in the table in some color, depending on availability, use something like this:
$servers = [ordered]#{
"Server 1" = "127.0.0.1"
"Server 2" = "127.0.0.1"
"Server 3" = "127.0.0.1"
}
$virtuals = [ordered]#{
"VM 1" = "127.0.0.1"
"VM 2" = "127.0.0.1"
"VM 3" = "127.0.0.1"
}
Write-Host "Check available servers" -ForegroundColor Cyan
$svr = foreach ($key in $servers.GetEnumerator()){
if ((Test-Connection $key.Value -Count 3 -Quiet)){
[pscustomobject]#{Server = $key.Key; Status = "Available"}
}
else{
[pscustomobject]#{Server = $key.Key; Status = "Not available"}
}
}
# output this as colored table
$svr | Format-Table | Out-String -Stream | ForEach-Object {
$color = if ($_ -match 'Not available') { 'Red' } else { 'Green' }
Write-Host $_ -ForegroundColor $color
}
Write-Host
# now do the same for the VMs
Write-Host "Check available virtuals" -ForegroundColor Cyan
$vms = foreach ($key in $virtuals.GetEnumerator()){
if ((Test-Connection $key.Value -Count 3 -Quiet)){
[pscustomobject]#{VM = $key.Key; Status = "Available"}
}
else{
[pscustomobject]#{VM = $key.Key; Status = "Not available"}
}
}
# output this as colored table
$vms | Format-Table | Out-String -Stream | ForEach-Object {
$color = if ($_ -match 'Not available') { 'Red' } else { 'Green' }
Write-Host $_ -ForegroundColor $color
}
Output:
As PowerShell has already added the titles to the tops of the columns from the previous item, it doesn't add them again. Part of its way to reduce repetition or something probably.
You could maybe do an output using Write-Host and then you can format to your hearts content.
Write-Host "Servers" -ForegroundColor Cyan
Write-Host "Virtuals" -ForegroundColor Cyan
You could also do something like...
if ($status -eq "Available") {
$color = "Green"
} else {
$color = "Red"
}
Then when you come to write your results you could do...
Write-Host "Server Name" -ForegroundColor $color
Hope that makes sense, I can write something out fully if you need.

Enviroment Paths without overwriting String

I would like to ask question about how I should proceed or how I should fix the code.
My problem is that I need my code to write into the Path three different paths for Logstash, Kibana and ElasticSearch, but I have no idea how to do it. It returns always the same error about missing ")" error
Here's the whole code ¨
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[string]$NewLocation.GetType($ElasticSearch)
[string]$ElasticSearch = "C:\Elastic_Test_Server\elasticsearch\bin"
[string]$Kibana = "C:\Elastic_Test_Server\kibana\bin"
[string]$Logstash = "C:\Elastic_Test_Server\logstash\bin"
)
Begin
{
#Je potřeba spustit jako Administrátor
$regPath = "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
$hklm = [Microsoft.Win32.Registry]::LocalMachine
Function GetOldPath()
{
$regKey = $hklm.OpenSubKey($regPath, $FALSE)
$envpath = $regKey.GetValue("Path", "", [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
return $envPath
}
}
Process
{
# Win32API errory
$ERROR_SUCCESS = 0
$ERROR_DUP_NAME = 34
$ERROR_INVALID_DATA = 13
$NewLocation = $NewLocation.Trim();
If ($NewLocation -eq "" -or $NewLocation -eq $null)
{
Exit $ERROR_INVALID_DATA
}
[string]$oldPath = GetOldPath
Write-Verbose "Old Path: $oldPath"
# Zkontroluje zda cesta již existuje
$parts = $oldPath.split(";")
If ($parts -contains $NewLocation)
{
Write-Warning "The new location is already in the path"
Exit $ERROR_DUP_NAME
}
# Nová cesta
$newPath = $oldPath + ";" + $NewLocation
$newPath = $newPath -replace ";;",""
if ($pscmdlet.ShouldProcess("%Path%", "Add $NewLocation")){
# Přidá to přítomné session
$env:path += ";$NewLocation"
# Uloží do registru
$regKey = $hklm.OpenSubKey($regPath, $True)
$regKey.SetValue("Path", $newPath, [Microsoft.Win32.RegistryValueKind]::ExpandString)
Write-Output "The operation completed successfully."
}
Exit $ERROR_SUCCESS
}
Thank you for your help.
I really think you could simplify this a lot, unless I have misunderstood. Apologies, I am not currently on a Windows machine so can't test this.
function Add-ESPath {
# Create an array of the paths we wish to add.
$ElasticSearch = #(
"C:\Elastic_Test_Server\elasticsearch\bin",
"C:\Elastic_Test_Server\kibana\bin",
"C:\Elastic_Test_Server\logstash\bin"
)
# Collect the current PATH string and split it out in to an array
$CurrentPath = [System.Environment]::GetEnvironmentVariable("PATH")
$PathArray = $CurrentPath -split ";"
# Loop though the paths we wish to add.
foreach ($Item in $ElasticSearch) {
if ($PathArray -notcontains $Item) {
$PathArray += $Item
}
else {
Write-Output -Message "$Item is already a member of the path." # Use Write-Warning if you wish. I see it more as a notification here.
}
}
# Set the path.
$PathString = $PathArray -join ";"
Try {
[System.Environment]::SetEnvironmentVariable("PATH", $PathString)
exit 0
}
Catch {
Write-Warning -Message "There was an issue setting PATH on this machine. The path was:" # Use $env:COMPUTERNAME here perhaps instead of 'this machine'.
Write-Warning -Message $PathString
Write-Warning -Message $_.Exception.Message
exit 1
}
}
Add-ESPath
Perhaps you want to add some kind of log file rather than writing messages/warnings to the console. You can use Add-Content for this.
I long time ago i wrote some functions to add a path to system path + their is an check if the path is already inside the system path. And i also did an elevation check so when i use this function and i forgot to elevate my powershell that i get a warning. Its a different approach, I hope it will help you.
I only use the begin {} proccess{} statements for when i want to write a function that excepts pipeline inputs. So its if you want to write a function that will work as the following:
$paths = #("C:\Elastic_Test_Server\elasticsearch\bin", "C:\Elastic_Test_Server\kibana\bin")
$paths | my-append-these-to-system-path-function
Elevation check:
function G-AmIelevated($warningMessage){
if([bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match "S-1-5-32-544")){
return $true
}else{
write-host "not elevated $warningMessage" -ForegroundColor Red
return $false
}
}
append something to system path with check if its already inside system path:
function G-appendSystemEnvironmentPath($str){
if(test-path $str){
if(!((Get-Itemproperty -path 'hklm:\system\currentcontrolset\control\session manager\environment' -Name Path) -like "*$str*")){
write-host "`t $str exists...`n adding $str to environmentPath" -ForegroundColor Yellow
if(G-AmIelevated){
write-host `t old: (Get-Itemproperty -path 'hklm:\system\currentcontrolset\control\session manager\environment' -Name Path).Path
Set-ItemProperty -path 'hklm:\system\currentcontrolset\control\session manager\environment' `
-Name Path `
-Value "$((Get-Itemproperty -path 'hklm:\system\currentcontrolset\control\session manager\environment' -Name Path).Path);$str"
write-host `t new: (Get-Itemproperty -path 'hklm:\system\currentcontrolset\control\session manager\environment' -Name Path).Path
write-host `t restart the computer for the changes to take effect -ForegroundColor Red
write-host `t `$Env:Path is the merge of System Path and User Path This function set the system path
write-host `t $str appended to environmet variables. -ForegroundColor Green
}else{
write-host `t rerun ise in elevated mode -ForegroundColor Red
}
}else{
write-host "`t $str is in system environmenth path"
}
}else{
write-host `t $str does not exist
}
}
G-appendSystemEnvironmentPath -str "C:\Elastic_Test_Server\elasticsearch\bin"
G-appendSystemEnvironmentPath -str "C:\Elastic_Test_Server\kibana\bin"
G-appendSystemEnvironmentPath -str "C:\Elastic_Test_Server\logstash\bin"

Issue running an script block in powershell to get csv output

In powershell running the below code in a script block and having issue running it
foreach($list in $an){
Write-Host "on loop :" $loop
Write-Host "Checking on VM : "$list.vm
$checkdata = (([datetime]$currentdate) - ([datetime]$list.Created.ToString().split(" ")[0])).Days
Write-Host "Check data " $checkdata
IF($checkdata -gt 2){
Write-Host "on Dupe : " $dupe
#$datecreated = $sizeinGGB = $diff = $null | Out-Null
$datecreated = ($list.Created.ToString().split(" ")[0])
Write-Host $datecreated
$sizeinGGB = [INT]$list.SizeGB
Write-Host $sizeinGGB
$diff = ((([datetime]$currentdate) - ([datetime]$list.Created)).Days)
Write-Host $diff
$repo = [ordered] #{
vm = $list.vm
SNapshotname = $list.Name
DateCreated = $datecreated
Snapshotold = $diff
SizeinGB = $sizeinGGB
}
New-Object PSobject -Property $repo
$dupe ++
}ELSE{
Write-Host $list.vm " : Looks Good"
}
$loop ++
}
If I remove the $repo assignment statement my script is working good. If I put that on the script then script just stop execution on $repo block

Citrix Application list with assigned groups

The following script gives me the list I want but I need to save the output to a file:
asnp citrix*
$apps = Get-BrokerApplication -MaxRecordCount 10000 -AdminAddress khonemdc75ddc01;
$apps | ForEach-Object {
$array = $_.AssociatedDesktopGroupUids
foreach ($element in $array) {
$policy = Get-BrokerAccessPolicyRule –DesktopGroupUid $element -AllowedConnections NotViaAG
write-host "Application: " $_.ApplicationName
if ($_.AssociatedUserNames)
{
write-host "Users configured using Visibility:" $_.AssociatedUserNames
write-host '--------------------'
}
else
{
write-host "Users with access inherited from DG:"
$policy.IncludedUsers;
write-host '--------------------'
}
}
}
If you use the Write-Hostcmdlet, you won't be able to pipe the output to a file - just write the string to the pipeline. To save the output, you can use the Out-File cmdlet:
asnp citrix*
$apps = Get-BrokerApplication -MaxRecordCount 10000 -AdminAddress khonemdc75ddc01;
$apps | ForEach-Object {
$array = $_.AssociatedDesktopGroupUids
foreach ($element in $array) {
$policy = Get-BrokerAccessPolicyRule –DesktopGroupUid $element -AllowedConnections NotViaAG
"Application: $_.ApplicationName"
if ($_.AssociatedUserNames)
{
"Users configured using Visibility: $_.AssociatedUserNames"
'--------------------'
}
else
{
"Users with access inherited from DG: $policy.IncludedUsers;"
'--------------------'
}
}
} | Out-File -FilePath 'your_file.txt'
Use write-ouput instead out write-host and at the end just pipe it at the end > c:\test.txt