I have written the following script to compare jobs that I have saved in a folder and compare them by name on the servers.
$submaporiginal = 'D:\Jobs_from_Server\TEST_Jobs_Aangepast'
$SqlServer1Name = "servername"
$SqlServer1 = New-Object Microsoft.SqlServer.Management.Smo.Server($SqlServer1Name)
$files = Get-ChildItem $submaporiginal *.sql
$SqlServer1JobListing = $SqlServer1.JobServer.Jobs |
Select-Object -ExpandProperty Name
foreach ($file in $files)
{
$stap1 = $file.Name
$locatiedtsx = $stap1.IndexOf("_goed")
$SqlServer2JobListing = $stap1.Substring(0,$locatiedtsx)
}
Compare-Object $SqlServer1JobListing $SqlServer2JobListing
{
if ($_.SideIndicator -eq "<=")
{Write-Host $_}
}
After running it shows a list with all the jobs that are currently on the server but are not saved in the folder: TEST_Jobs_Aangepast
My problem is that currently it only ignores the last job that have run trough the foreach ($file in $files)
For excample in the map are the files TestA.sql and TestB.SQL while the server has a job named testA, TestB and TestC.
The result shown should be:
TestC <=
but the actual result is shows:
TestA <=
TestC <=
My question is how can I set all the values that go trough foreach ($file in $files) in one parameter SqlServer2JobListing so that all the jobs that match between $SqlServer1JobListing $SqlServer2JobListing are not shown
Your problem is that you always reassign the $SqlServer2JobListing variable, instead you need to add a value to array or list. Like this:
$SqlServer1JobListing = New-Object System.Collections.ArrayList
foreach ($file in $files)
{
$stap1 = $file.Name
$locatiedtsx = $stap1.IndexOf("_goed")
$SqlServer1JobListing.Add($stap1.Substring(0,$locatiedtsx))
}
This way, after your foreach loop you will get a collection of all the items, rather than only the last one like you had before.
Related
I have a large list of Customer IDs (40,000). Files for each Customer have been saved in many different locations. I first run a Test-Path to see if the directory exists, if it does then I run Get-ChildItem and filter down the results to find the file I need (Any file matching string 'Contract'). I am hoping to educate myself on how to speed this up, I have attempted to introduce another variable 'Trigger' to try and prevent some of the excess code from running if the matching file is found. It is taking a very long time to loop this through 40,000 times so if there is a better way any help greatly appreciated, many thanks.
Here is the code I'm currently using
ForEach ($Customer in $CustomerList)
{
$Trigger = 0
$Result1 = Test-Path "$Location1\$Customer"
$Result2 = Test-Path "$Location2\$Customer"
$Result3 = Test-Path "$Location3\$Customer"
IF ($Result1 -eq $True)
{
$1Files = GCI "$Location1\$Customer" -Recurse
ForEach ($File IN $1Files)
{
IF ($Trigger -eq 0)
{
$FileName = $File.Name
$FileLocation = $File.FullName
IF ($FileName -match 'Contract')
{
$Report += "$FileName $FileLocation"
$Trigger = 1
}
}
}
}
ELSEIF ($Result2 -eq True)
{
Same as result 1 codeblock but using $Location2
}
ELSEIF ($Result3 -eq True)
{
Same as result 1 codeblock but using $Location3
}
}
Complete novice to Powershell so, my apologies ahead of time for the likely easy task for most in this group.
$File = Get-ChildItem "C:\location"
$ACLs= foreach ($item in $File) {get-acl $item.FullName}
$foldernames = $acls.pschildname
$ACLNames = $acls.Access.IdentityReference
$ACLNamesNew = foreach ($ACLName in $ACLNames) {
$ACLNameString = $ACLname.Value.ToString()
$ACLNameFormatted = $ACLNameString.Split("\")[0]
}
Ultimate goal is to take the string, trim just the domain/group names from the string, pull only the unique values, and write whats left to the variable $ACLNames. Haven't even tried filtering unique as even the above leaves $ACLNamesNew empty. The foreach seams sound from my testing, but it doesn't write the values into the variable as I expected.
If you want to collect the result of a loop you have to output something inside your loop. This should be enough .. if I've got you right
$fileList = Get-ChildItem 'C:\location'
$ACLList = foreach ($file in $fileList) { get-acl $file.FullName }
$ACLNameList = $ACLList.Access.IdentityReference
$ACLNameNewList = foreach ($ACLName in $ACLNameList) {
$ACLname.Value.ToString().Split("\")[0]
}
$ACLNameNewList
Right now, I have a CSV file which contains 3,800+ records. This file contains a list of server names, followed by an abbreviation stating if the server is a Windows server, Linux server, etc. The file also contains comments or documentation, where each line starts with "#", stating it is a comment. What I have so far is as follows.
$file = Get-Content .\allsystems.csv
$arraysplit = #()
$arrayfinal = #()
[int]$windows = 0
foreach ($thing in $file){
if ($thing.StartsWith("#")) {
continue
}
else {
$arraysplit = $thing.Split(":")
$arrayfinal = #($arraysplit[0], $arraysplit[1])
}
}
foreach ($item in $arrayfinal){
if ($item[1] -contains 'NT'){
$windows++
}
else {
continue
}
}
$windows
The goal of this script is to count the total number of Windows servers. My issue is that the first "foreach" block works fine, but the second one results in "$Windows" being 0. I'm honestly not sure why this isn't working. Two example lines of data are as follows:
example:LNX
example2:NT
if the goal is to count the windows servers, why do you need the array?
can't you just say something like
foreach ($thing in $file)
{
if ($thing -notmatch "^#" -and $thing -match "NT") { $windows++ }
}
$arrayfinal = #($arraysplit[0], $arraysplit[1])
This replaces the array for every run.
Changing it to += gave another issue. It simply appended each individual element. I used this post's info to fix it, sort of forcing a 2d array: How to create array of arrays in powershell?.
$file = Get-Content .\allsystems.csv
$arraysplit = #()
$arrayfinal = #()
[int]$windows = 0
foreach ($thing in $file){
if ($thing.StartsWith("#")) {
continue
}
else {
$arraysplit = $thing.Split(":")
$arrayfinal += ,$arraysplit
}
}
foreach ($item in $arrayfinal){
if ($item[1] -contains 'NT'){
$windows++
}
else {
continue
}
}
$windows
1
I also changed the file around and added more instances of both NT and other random garbage. Seems it works fine.
I'd avoid making another ForEach loop for bumping count occurrences. Your $arrayfinal also rewrites everytime, so I used ArrayList.
$file = Get-Content "E:\Code\PS\myPS\2018\Jun\12\allSystems.csv"
$arrayFinal = New-Object System.Collections.ArrayList($null)
foreach ($thing in $file){
if ($thing.StartsWith("#")) {
continue
}
else {
$arraysplit = $thing -split ":"
if($arraysplit[1] -match "NT" -or $arraysplit[1] -match "Windows")
{
$arrayfinal.Add($arraysplit[1]) | Out-Null
}
}
}
Write-Host "Entries with 'NT' or 'Windows' $($arrayFinal.Count)"
I'm not sure if you want to keep 'Example', 'example2'... so I have skipped adding them to arrayfinal, assuming the goal is to count "NT" or "Windows" occurrances
The goal of this script is to count the total number of Windows servers.
I'd suggest the easy way: using cmdlets built for this.
$csv = Get-Content -Path .\file.csv |
Where-Object { -not $_.StartsWith('#') } |
ConvertFrom-Csv
#($csv.servertype).Where({ $_.Equals('NT') }).Count
# Compatibility mode:
# ($csv.servertype | Where-Object { $_.Equals('NT') }).Count
Replace servertype and 'NT' with whatever that header/value is called.
I've written a PowerShell function to create a custom object and stores it into a hashtable. The issue I'm facing is retrieving that object. I need to retrieve that object because it contains an array, I need to loop through that array and write it to a text file.
function removeItem {
<#Madatory Parameters for function, it takes the path to the files/folders
to clean up and path to the hashtable.#>
Param([Parameter(Mandatory=$True)]
[string]$path,
[string]$writetoText,
[hashtable] $hashWrite=#{}
)
<#Begin if statement: Test if Path Exists#>
if (Test-Path ($path)) {
<#Begin if statement: Check if file is Directory#>
if ((Get-Item $path) -is [System.IO.DirectoryInfo]) {
$pathObj = [pscustomobject]#{
pathName = $path
Wipe = (Get-ChildItem -Path $path -Recurse)
Count = (Get-ChildItem -Path $path -Recurse | Measure-Object).Count
}
# Write-Output $pathObj.Wipe
#Add Data to Hashtable
$hashWrite.Add($pathObj.pathName,$pathObj)
foreach ($h in $hashWrite.GetEnumerator()) {
Write-Host "$($h.Name): $($h.Value)"
}
<#
[string[]]$view = $pathObj.Wipe
for ($i=0; $i -le $view.Count; $i++){
Write-Output $view[$i]
}
#>
$pathObj.pathName = $pathObj.pathName + "*"
}<#End if statement:Check if file is Directory #>
}
}
My function takes 3 arguments, a path, the text file path, and a hashtable. Now, I create a custom object and store the path, files/folders contained in that path, and the count. Now, my issue is, I want to retrieve that custom object from my hashtable so that I can loop though the Wipe variable, because it's an array, and write it to the text file. If I print the hashtable to the screen it see the Wipe variable as System.Object[].
How do I retrieve my custom object from the hash table so I can loop through the Wipe Variable?
Possible Solution:
$pathObj = [pscustomobject]#{
pathName = $path
Wipe = (Get-ChildItem -Path $path -Recurse)
Count = (Get-ChildItem -Path $path -Recurse | Measure-Object).Count
}
#Add Data to Hashtable
$hashWrite.Add($pathObj.pathName,$pathObj)
foreach ($h in $hashWrite.GetEnumerator()) {
$read= $h.Value
[string[]]$view = $read.Wipe
for ($i=0; $i -le $view.Count; $i++) {
Write-Output $view[$i]
}
}
Is this the ideal way of doing it?
There are uses for GetEnumerator(), but in your case you're better off just looping over the keys of the hashtable:
$hashWrite.Keys | % {
$hashWrite[$_].Wipe
} | select -Expand FullName
I have a list of files in a folder each are in this format: custID_invID_prodID. For every file I need to break it into sections based on '_'. Currently I have this code
$files = Get-ChildItem test *.txt
$Part = $files.Split(';')[$($files.Split('_').Count-1)]
Write-Host "${Part}"
The problem is that it appears that $files is a list of all the files and I need it to run each file on its own. Can anyone offer some pointers on how to do this for the entire folder?
"The problem is that it appears that $files is a list of all the files and I need it to run each file on its own."
That is correct, running get-childitem on a folder will give you a list of all files (and subfolders). In order to go through them one by one, you need a loop:
$file = #()
$files = Get-ChildItem Test *.txt
foreach($f in $files)
{
$file += ([String]$f).Split("_")
$count = ([String]$f).Split("_") | Measure-Object | select count
}
if($count.count -eq 3) {
for($i=2; $i -lt $file.length; $i+=3) {
$file[$i] = $file[$i].trimend(".txt")
}
}
I was able to fix this by using this code:
$Part = $file.name.Split('_')[$($file.name.Split('_').Count-1)]
Write-Host "${Part}"