Powershell script causing overflow - sql-server

I am running the following Powershell Script against a list of SQL Instances to return Instance information, including users and roles. I want to use Powershell to do this as I'm collating the data and will import into another system which will do some analysis.
I created the following script which creates an XML file output for each instance found. The script works great (yes, it's probably clunky and an awful way to do this, but I'm learning so please feel free to give me a shove in the right direction), however for one of the servers with a few hundred SQL logins I get an overflow message appear on screen, the XML file is not closed correctly and as a result I can't import the results into my analysis system.
I would like either:
Ideas on what could be causing the overflow. For reference, the output XML that crashes out is 2.5MB in size, with approx 39,000 lines in the XML output before the overflow occurs
[OR]
Another way to get this output - CSV is an option but I don't know enough how to output this - can anyone provide tips?
Thank you in advance
#Input file is a plain text file with the name of each of the instances listed in it
$InputFile="C:\Tasks\SQL\Permissions\in\Instances.txt"
$OutputFolder="\\networkdrive\sharedfolder\"
Function GetDBUserInfo($Dbase)
{
if ($dbase.status -eq "Normal") # ensures the DB is online before checking
{$users = $Dbase.users | where {$_.login -eq $SQLLogin.name} # Ignore the account running this as it is assumed to be an admin account on all servers
foreach ($u in $users)
{
if ($u)
{
$XmlWriter.WriteStartElement("Login")
$XmlWriter.WriteElementString('DBName', $dbase.name)
$XmlWriter.WriteElementString('LoginName', $SQLLogin.name)
$XmlWriter.WriteStartElement('Login_Roles')
$DBRoles = $u.enumroles()
foreach ($role in $DBRoles)
{
$XmlWriter.WriteElementString('Role', $Dbase.name)
}
$XmlWriter.WriteEndElement()#Login_Roles
#Get any explicitly granted permissions
$XmlWriter.WriteStartElement('Login_Permissions')
$XmlWriter.WriteElementString('Instance', $svr.name)
$XmlWriter.WriteElementString('DBName', $dbase.name)
$XmlWriter.WriteElementString('LoginName', $SQLLogin.name)
foreach($perm in $Dbase.EnumObjectPermissions($u.Name))
{
$XmlWriter.WriteElementString('Permissions', $perm.permissionstate.tostring() + " " + $perm.permissiontype.tostring() + " on " + $perm.objectname.tostring() + " in " + $DBase.name.tostring())
}
$XmlWriter.WriteEndElement() #Login_Permissions
$XMLWriter.WriteEndElement() #Login
} # Next user in database
}
#else
#Skip to next database.
}
}
#Main portion of script start
[reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null #ensure we have SQL SMO available
foreach ($SQLsvr in get-content $InputFile) # read the instance source file to get instance names
{
$svr = new-object ("Microsoft.SqlServer.Management.Smo.Server") $SQLsvr
#Cycle through each instance and write the instance information to the file
#Output file is base folder for each of the text files (which will be named for the instance)
$OutputFile = $svr.name
$OutputFile = $OutputFolder+$OutputFile.Replace("\", "-")+".xml"
# get an XMLTextWriter to create the XML
$XmlWriter = New-Object System.XMl.XmlTextWriter($OutputFile,$Null)
# choose a pretty formatting:
$xmlWriter.Formatting = 'Indented'
$xmlWriter.Indentation = "4"
# write the header
$xmlWriter.WriteStartDocument()
# set XSL statements
$XLSPropText="type='text/xsl' href='style.xsl'"
$xmlWriter.WriteProcessingInstruction("xml-stylesheet", $XSLPropText)
# create root element "instances" and add some attributes to it
$xmlWriter.WriteStartElement("Root")
$XmlWriter.WriteStartElement("Instance")
$XmlWriter.WriteElementString("SQLInstance", $svr.name)
$XmlWriter.WriteElementString("SQLVersion", $svr.VersionString)
$XmlWriter.WriteElementString("Edition", $svr.Edition)
$XmlWriter.WriteElementString("LoginMode", $svr.loginmode)
$XmlWriter.WriteEndElement #instance
$SQLLogins = $svr.logins
foreach ($SQLLogin in $SQLLogins)
{
#Iterate through each login, writing the details into the login details
#$XmlWriter.WriteComment("Login Details")
$xmlWriter.WriteStartElement("Logins")
$XmlWriter.WriteElementString("InstanceName", $svr.Name)
$XmlWriter.WriteElementString("LoginName", $SQLLogin.Name)
$XmlWriter.WriteElementString("LoginType", $SQLLogin.LoginType)
$XmlWriter.WriteElementString("Created", $SQLLogin.CreateDate)
$XmlWriter.WriteElementString("DefaultDatabase", $SQLLogin.DefaultDatabase)
$XmlWriter.WriteElementString("Disabled", $SQLLogin.IsDisabled)
$SQLRoles = $SQLLogin.ListMembers()
If ($SQLRoles)
{ $XmlWriter.WriteElementString("ServerRole", $SQLRoles) }
else
{ $XmlWriter.WriteElementString("ServerRole", "Public") }
If ( $SQLLogin.LoginType -eq "WindowsGroup" )
{ #get individuals in any Windows domain groups
$XmlWriter.WriteStartElement("WindowsLogins")
$XmlWriter.WriteElementString("InstanceName", $svr.name)
$XmlWriter.WriteElementString("Login", $SQLLogin.name)
try {
$ADGRoupMembers = get-adgroupmember $SQLLogin.name.Split("\")[1] -Recursive
foreach($member in $ADGRoupMembers)
{ $XmlWriter.WriteElementString("Account", $member.name.tostring() + "(" + $member.SamAccountName.tostring() +")") }
}
catch
{
#Sometimes there are 'ghost' groups left behind that are no longer in the domain, this highlights those still in SQL
$XmlWriter.WriteElementString("Account", "Unable to locate group " + $SQLLogin.name.Split("\")[1] + " in the AD Domain")
}
$XmlWriter.WriteEndElement()
}
#Check the permissions in the DBs the Login is linked to.
If ($SQLLogin.EnumDatabaseMappings())
{
$XmlWriter.WriteStartElement('Permissions')
$XmlWriter.WriteElementString('InstanceName', $svr.name)
$xmlwriter.WriteElementString('Login', $SQLLogin.name)
foreach ( $DB in $svr.Databases)
{
try {
GetDBUserInfo($DB)
}
catch
{
echo $_.Exception|format-list -force
}
} # Next Database
$XmlWriter.WriteEndElement()
}
Else
{
$XmlWriter.WriteStartElement('Permissions')
$XmlWriter.WriteElementString('InstanceName', $svr.name)
$xmlwriter.WriteElementString('Login', $SQLLogin.name)
$XmlWriter.WriteElementString('Permissions', 'No Permissions')
$XmlWriter.WriteEndElement()
}
$xmlWriter.WriteEndElement() #End Logins element
}
}
# close the "machines" node:
$xmlWriter.WriteEndElement() #root node
# finalize the document:
$xmlWriter.WriteEndDocument()
$xmlWriter.Flush()
$xmlWriter.Close()
When running, error message is:
OverloadDefinitions
--------------------
void WriteEndElement()
void WriteEndElement()
No other error or message is given. The file does get written but is incomplete.

Related

Strange behavior of PowerShell code - returns wrong result unless session is restarted

I have this code which check for the existence of a project in SSISDB. On the first run I make sure the project is there and it returns the correct value. But then I delete the project and run the code again but it then returns 1 again. When I restart the session then it starts to return the correct answer again. What is the problem and how can I solve it?
import-module sqlserver;
$TargetInstanceName = "localhost\default"
$TargetFolderName = "FolderForTesting";
$ProjectName = "ProjectTesting";
$catalog = Get-Item SQLSERVER:\SSIS\$TargetInstanceName\Catalogs\SSISDB\
$folder = $catalog.Folders["$TargetFolderName"];
$project = $folder.Projects["$ProjectName"];
if($null -eq $project){
Return 0
} else {
Return 1
}
Combining mine and Theo's helpful comments into a possible solution:
import-module sqlserver;
$TargetInstanceName = "localhost\default"
$TargetFolderName = "FolderForTesting";
$ProjectName = "ProjectTesting";
try {
$catalog = Get-Item SQLSERVER:\SSIS\$TargetInstanceName\Catalogs\SSISDB\
$folder = $catalog.Folders[ $TargetFolderName ]
$project = $folder.Projects[ $ProjectName ]
if($null -eq $project){
Return 0
} else {
$project.Refresh() # Causes an exception if project actually doesn't exist
Return 1
}
}
catch {
return 0
}
This is based on Refreshing the SQL Server PowerShell Provider and PS + SQLPS refreshing the SQL Server object and your own testing. I couldn't find any official information regarding the topic.

Trying to Import an XML file into a MS SQL table using PowerShell

I am trying to import an XML file into a MS SQL table using PowerShell, I have modified a PowerShell script I already had that worked fine but could do with some help as the new XML file has multiple entries for some elements.( I have included a sample of the XML file)
Table layout is below and as is a sample of the file I am trying to import and also my script I am trying to modify to get working.
Table layout is:
------------------------------
:supplier_id : name : Symbol :
and here is an part of the XML file itself
<SupplierMapping supplier_id="4536" name="Joby">
<Symbol>Joby</Symbol>
</SupplierMapping>
<SupplierMapping supplier_id="4537" name="ACT">
<Symbol>ACT</Symbol>
<Symbol>ADVANCED CABLE TECH</Symbol>
<Symbol>ADVANCED CABLE TECHNOLOGY</Symbol>
<Symbol>IEC LOCK</Symbol>
</SupplierMapping>
As you can see some supplier id's and names will have multiple <Symbol> names so I would like to have multiple entries in my table for those, however the script I have modified only seems to pull in the supplier_id and name elements and misses the <Symbol> part entirely. any help or guidance would be much appreciated.
Set-ExecutionPolicy Unrestricted -Scope LocalMachine
[String]$global:connectionString = "Data Source=Apps2\Apps2;Initial Catalog=DTEDATA;Integrated Security=SSPI";
[System.Data.DataTable]$global:dt = New-Object System.Data.DataTable;
[System.Xml.XmlTextReader]$global:xmlReader = New-Object System.Xml.XmlTextReader("C:\Scripts\icecat\supplier_mapping.xml");
[Int32]$global:batchSize = 100;
function Add-FileRow() {
$newRow = $dt.NewRow();
$null = $dt.Rows.Add($newRow);
$newRow["supplier_id"] = $global:xmlReader.GetAttribute("supplier_id");
$newRow["name"] = $global:xmlReader.GetAttribute("name");
$newRow["Symbol"] = $global:xmlReader.GetAttribute("Symbol");
}
# init data table schema
$da = New-Object System.Data.SqlClient.SqlDataAdapter("SELECT * FROM Supplier_Mapping_Test WHERE 0 = 1", $global:connectionString);
$null = $da.Fill($global:dt);
$bcp = New-Object System.Data.SqlClient.SqlBulkCopy($global:connectionString);
$bcp.DestinationTableName = "dbo.Supplier_Mapping_Test";
$recordCount = 0;
while ($xmlReader.Read() -eq $true) {
if (($xmlReader.NodeType -eq [System.Xml.XmlNodeType]::Element) -and ($xmlReader.Name -eq "SupplierMapping"))
Add-FileRow -xmlReader $xmlReader;
$recordCount += 1;
if (($recordCount % $global:batchSize) -eq 0) {
$bcp.WriteToServer($dt);
$dt.Rows.Clear();
Write-Host "$recordCount file elements processed so far";
}
}
}
if ($dt.Rows.Count -gt 0) {
$bcp.WriteToServer($dt);
}
$bcp.Close();
$xmlReader.Close();
Write-Host "$recordCount file elements imported ";
catch {
throw;
}

How do i use PSGSUITE PS module to add google groups?

Ok so I work for a small business, and they use a google spread sheet as the "Phone list"
for finding and contacting employees. I installed the PSGSUITE powershell module and it seems to work very well, but im new to powershell and coding in general. The filter sheet i made along with the phone list places the employees in there respective groups. Example then The code.
"phone list"
Name # Company code Ext. Department Job Title Email
Hayden 111-222-333 JOP IT Technician example#example.com
"filter 2sheet"
JOP SPD
hayden#.com lisa#.com
john#.com arron#.com
david#.com mike#.com
I want to add these emails to there respective google groups
## NOVA BEAZ ##
## add groups in google based on company title
###
####
# Import Modules
Import-Module PSGSuite
# Create Array of Groups
$Title = (Import-GSSheet -SpreadsheetId "1NtCT5ruoL4Kf4-ec55xe-L8esXcSY8orfd-zOFK4q4k" -SheetName "Filter" -Headers "None" -Range "A1:1")
$Title = $Title | % { $_ }
$Groups = (Get-GSgroup -Fields "Name" )
if($Title = $Groups)
#{add that users email to the group}
#else
{echo "there is now group that matches that"}
The main issue is I really just dont know how to correctly run through the arrays and select all the emails in that row to add to the google groups, I think I need a array or object list form of storing my emails, I want this to be dynamic.
Excerpts from my blog post on how to use the PSGusite module.
Please check if the following answers your question. If not, let me know.
User Process
To begin, we need to import the module and then use the command Get-GSDriveFileList to find the Google Sheet where our data is stored.
Next, we use the command Import-GSSheet to import our user and group data.
Get Data from GSheet
# Import module
Import-Module -Name PSGSuite
# Discover spreadsheet Id in drive file list
$Spreadsheet = Get-GSDriveFileList -Filter "name = 'UserManagement'"
# Get data from each sheet from Google spreadsheet
$UserData = Import-GSSheet -SpreadsheetId $Spreadsheet.Id -SheetName 'Users'
$GroupData = Import-GSSheet -SpreadsheetId $Spreadsheet.Id -SheetName 'Groups'
Create Organization Units
We use Get-GSOrganizationalUnit to determine if the OU exists. And then we use New-GSOrganizationalUnit to create it if it does not.
foreach ($Group in $GroupData) {
$SplitPath = $Group.OrgUnitPath -Split '/'
$ParentPath = $SplitPath[0..($SplitPath.Count -2)] -join '/'
$OUPath = $SplitPath[-1]
$OrgUnit = Get-GSOrganizationalUnit -SearchBase $Group.OrgUnitPath -SearchScope Base -ErrorAction SilentlyContinue
if ($OrgUnit) {
"Org Unit {0} exists at {1}" -f $OrgUnit.OrgUnitPath,$OrgUnit.ParentOrgUnitPath
} else {
"Org Unit {0} does not exist; attempting to create in {1}" -f $Group.OrgUnitPath,$ParentPath
try {
$GSOrgUnit = New-GSOrganizationalUnit -Name $OUPath.ToLower() -ParentOrgUnitPath $ParentPath -Description $Group.Description
"Created {0} : {1}" -f $GSOrgUnit.OrgUnitPath,$GSOrgUnit.Description
}
catch {
"Unable to create {0}" -f $Group.OrgUnitPath
}
}
}
Create Groups
Using the command Get-GSGroup, we check if the group exists. If the group does not already exist, use New-GSGroup to create the group from the spreadsheet.
foreach ($Group in $GroupData) {
$GSGroup = Get-GSGroup -Group $Group.Name -ErrorAction SilentlyContinue
if ($GSGroup) {
"Group {0} exists" -f $Group.Name
} else {
"Group {0} does not exist; attempting to create" -f $Group.Name
try {
$NewGSGroup = New-GSGroup -Name $Group.Name -Email $Group.Email -Description $Group.Description
"Created {0} : {1}" -f $NewGSGroup.Name,$NewGSGroup.Description
}
catch {
"Unable to create {0}" -f $Group.Name
}
}
}
Create Users
Create the users listed in the spreadsheet.
First, determine the department based on the user type.
Using the department, set the variable for the org unit path.
Create the required hashtable for CustomSchemas to add the EmployeeType to the user.
Generate a random secure password.
Using the command New-GSUser, create the new user.
If the user is successfully created, use the command New-GSUserAlias for best effort to create an email alias based on the user’s full name.
foreach ($User in $UserData) {
$Domain = $User.Email.Split('#')[1]
switch ($User.UserType) {
'Faculty' { $Department = 'Academics'}
'Staff' { $Department = 'Business' }
}
# Set OU path
$OrgUnitPath = $GroupData.Where({$_.Name -eq $Department}).OrgUnitPath
# Set employee type custom schema
$CustomSchemas = #{
CustomUniversity = #{
EmployeeType = $User.UserType
}
}
# Set a random secure string
$Password = ConvertTo-SecureString -String (Get-RandomPassword) -AsPlainText -Force
$NewGSUserParams = #{
PrimaryEmail = $User.Email
FullName = $User.FullName
GivenName = $User.GivenName
FamilyName = $User.FamilyName
OrgUnitPath = $OrgUnitPath
CustomSchemas = $CustomSchemas
Password = $Password
}
$NewUser = New-GSUser #NewGSUserParams -ErrorAction SilentlyContinue
if ($NewUser) {
'Created user {0} with primary email {1}' -f $User.FullName,$User.Email
} else {
'Failed to create user {0}' -f $User.Email
}
New-GSUserAlias -User $NewUser.PrimaryEmail -Alias ( $NewUser.Name.FullName.Replace(' ',''),$Domain -join '#') -ErrorAction SilentlyContinue | Out-Null
}
The Get-RandomPassword function is a mock-up. You would need to provide your own password method.
You can omit CustomSchemas from the hashtable. The blog post shows how to manually create new attributes, if you are interested.
Assign Users to Groups
Next, we use Get-GSUserList to get a list of all users in the parent OU, and then add the user to the group with Add-GSGroupMember.
$UserToGroupList = Get-GSUserList -SearchBase '/test' -SearchScope Subtree
foreach ($User in $UserToGroupList) {
switch -regex ($User.OrgUnitPath) {
'academics' { $GroupName = 'Academics'}
'business' { $GroupName = 'Business'}
}
try {
Add-GSGroupMember -Identity $GroupName -Member $User.User -ErrorAction Stop | Out-Null
'Added {0} to group {1}' -f $User.User,$GroupName
}
catch {
'Failed to add {0} to group {1}' -f $User.User,$GroupName
}
}
Note: I manually created a /test organizational unit and blocked automatic assignment of a license since I’m using my personal G Suite account. I don’t want any surprises at the end of the month.

Array index out of bounds. Interface Packets dropped: String (PowerShell)

Wrote a script to create incidents (objects) in bulk in SCSM (Microsoft System Center Service Manager) using PowerShell. The script pulls the data required from a CSV file. I am running into the following error:
New-SCSMIncident : Index was outside the bounds of the array.
At C:\Users\portalservice\Desktop\scripts\Incidents\BULK_Create_Incidents.ps1:83 char:5 + New-SCSMIncident -Title $Title -Description $Description -AffectedUser $Affe ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (Interface Packets Dropped :String) [New-SCSMIncident], IndexOutOfRangeException
+ FullyQualifiedErrorId : NewIncident,SMLets.SCSMIncidentNew
When I echo the contents of the array I see normal data... it all looks correct. Here is my script:
# Script designed to create tickets in bulk, reading the information needed from a CSVfile
# Tailored for incidents, can be modified to work with any work item
# SirLearnAlot 2015
# NOTES: Modify the $path variable to match the path of the data file being imported
# Import the smlets module
ipmo SMLets
Write-Host ""
Write-Host "Importing Smlets..."
# ---------------------------------------- Variable Decleration ----------------------------------------
Write-Host "Getting the classes needed..."
# Get the incident class
$IncidentClass = Get-SCSMClass -Name System.WorkItem.Incident$
# Get the CI Class
$CIClass = Get-SCSMClass -Name COMPANY.CI.Class$
# Get the Relationship we want to add (Affected Items)
$RelWIaboutCI = Get-SCSMRelationshipClass -Name System.WorkItemAboutConfigItem$
# Clear the error variable incase it contains anything already
$error.clear()
# --------------------------------------------- Data Import --------------------------------------------
# Import the CSV Data file containing list of incidents to create and their information
Write-Host "Importing CSV Data File..."
$path = "C:\Users\portalservice\Desktop\Script Data\Work Item Creation\Incidents\11.12.15\data.csv"
$data = ipcsv $path
if ($error -like "Could not find file *")
{
Write-Host "Encountered an error while importing the data file from '$path'. Please verify the path directories and file exist and run the script again."
exit
}
else
{
Write-Host "Successfully imported data file!"
Write-Host "Beginning ticket creation..."
#pause
}
# ---------------------------------------------- Execution ---------------------------------------------
# Begin going through file line by line
foreach ($case in $data)
{
# Clear the error variable
$error.clear()
# Visual Formatting
Write-Host ""
Write-Host "----------------------------------------------------------------------------------------"
Write-Host ""
# GETTING THE INFORMATION FROM DATA FILE AND STORING IN VARIABLES
# Get the Info for the Incident to create
$Title = $case.Title
Write-Host "Got case title: $Title"
$Description = $case.Description
Write-Host "Got case description: $Description"
$AffectedUser = $case.AffectedUser
Write-Host "Got case affected user: $AffectedUser"
$Classification = $case.Classification
Write-Host "Got case classification: $Classification"
$Impact = $case.Impact
Write-Host "Got case impact: $Impact"
$Urgency = $case.Urgency
Write-Host "Got case urgency: $Urgency"
$SupportGroup = $case.SupportGroup
Write-Host "Got case support group: $SupportGroup"
$PrimaryOwner = $case.PrimaryOwner
Write-Host "Got case owner: $PrimaryOwner"
$Vendor = $case.Vendor
Write-Host "Got case vendor: $Vendor"
$Customer = $case.Customer
Write-Host "Got case customer: $Customer"
$ReportedOn = $case.ReportedOn
Write-Host "Got date reported on: $ReportedOn"
# Get the name of the correct CI to add
$CIToAddNum = $case.CI
Write-Host "Got case CI: $CIToAddNum"
# Apply the non-OOB Values to the property hash table
$PropertyHashTable = #{"Vendor" = $Vendor; "Customer" = $Customer; "Reported_On" = $ReportedOn}
# INCIDENT CREATION
Write-Host "Attemping to create Incident from case data..."
New-SCSMIncident -Title $Title -Description $Description -AffectedUser $AffectedUser -Classification $Classification -Impact $Impact -Urgency $Urgency -SupportGroup $SupportGroup -Bulk
# Checks to see if the there is an error, if so displays a warning message and exits
if (!$error)
{
Write-Host "Incident creation successful."
}
else
{
Write-Host "$error"
Write-Host "Error creating the incident. Check the incident creation code and run this script again."
exit
}
# INCIDENT RETRIEVAL (POST-CREATION)
Write-Host "Attempting to retrieve incident for modification (Adding Customer, Vendor, and Reported On date to ticket)"
$Incident = Get-SCSMObject -Class $IncidentClass -Filter "Description -like '%$Description%'"
# Checks to see if the retrieval failed, if so displays error message and exits script
if ($Incident = $null)
{
Write-Host "Incident retrieval failed. Check the incident retrieval code and run the script again."
exit
}
# Apply the property hash table to the retrieved incident
$Incident | Set-SCSMObject -PropertyHashtable $PropertyHashTable
# ADDING THE CI TO THE INCIDENT
# Get the CI from the CMDB
$CIToAdd = Get-SCSMObject -Class $CIClass -Filter "DisplayName -eq '$CIToAddNum'"
if ($CIToAdd = $null)
{
Write-Host "Cannot find $CIToAddNum in the database, this CI does not seem to exist or the code to retrieve the CI failed. Please import the CI into the SMDB or fix the retrieval code and run this script again"
exit
}
# Attempt to add the CI to the Incident (Create a new relationship)
# Note: Due to a bug the -bulk paramater is required
Write-Host "Attempting to add $CIToAddNum to Incident..."
New-SCSMRelationshipObject -Relationship $RelWIaboutCI -Source $Incident -Target $CIToAdd -bulk
# Check if script throws error (cannot find the CI from the data file in our SMDB)
# If so provides error message and exits, otherwise provides success message
if ($error -like "Cannot bind argument to parameter 'Target' because it is null.")
{
Write-Host "Encountered an error while trying to add $CIToAddNum to $IncidentNum, this CI is not in the Service Manager Database or there was a problem retrieving it. Please import the CI into the SMDB or check the retrieval code and run this script again"
exit
}
else
{
Write-Host "Successfully Added!"
}
}
Write-Host ""
Write-Host "Success! All Incidents Corrected :)"
Not sure what the problem is here, any ideas?
Hit this same problem, my solution was to instead use New-SCSMObject.
Here is a simple example:
$irprops = #{Title = 'test'
Description = 'test descripton'
Impact = (get-scsmenumeration -name 'System.WorkItem.TroubleTicket.ImpactEnum.Low')
Urgency = (get-scsmenumeration -name 'System.WorkItem.TroubleTicket.UrgencyEnum.Medium')
ID = "IR{0}"
Status = (get-scsmenumeration -name 'System.WorkItem.TroubleTicket.ImpactEnum.Low')
Priority = 2
}
$ir=new-scsmobject -Class (get-scsmclass -name 'System.WorkItem.Incident$') -PropertyHashtable $irprops -PassThru

Powershell, Directory Verification

I am fairly new to PowerShell. I have created an exe that can be ran by a coworker that will go to 8 separate sql servers, to individual directories and check them for a list of created files. My current code checks for age less than one day and that it's not empty, however, I have been presented with a new problem. I need to be able to take a list in a text file/array/csv/etc and compare the list to the directory to ensure that there are not any additional files in the folder. All of the information is then formatted, exported to a file, and then emailed to certain recipients.
My question is, how do I create a script that works using this idea; preferably without considerable change to my current code as it is fairly length considering the sub directories of the 8 sql servers.. (current script redacted is as follows):
$today = get-date
$yesterday = $today.AddDays(-1)
$file_array = "XXX_backup*.trn", "XXX_backup*.bak", "XXY_backup*.trn", "XXY_backup*.bak"
$server_loc = \\hostname\e$\
$server_files = #(get-childitem $server_loc | where-object {$_.fullname -notmatch "(subdirectory)})
$server_complete_array = #("Files Directory ($server_loc)", " ")
foreach ($file in $files) {
IF ($file.length -eq 0) {
[string]$string = $file
$server_complete_Array = $server_complete_Array + "$string is empty."
}
elseif ($file.LastWriteTime -lt $yesterday) {
[string]$string = $file
$server_complete_Array = $server_complete_Array + "$string is old."
}
else {
[string]$string = $file
$server_complete_Array = $server_complete_Array + "$string is okay."}
}
Thank you for your help in advance. :)
Bit of a hack, but it should work with what you already have:
$file_array = "XXX_backup*.trn", "XXX_backup*.bak", "XXY_backup*.trn", "XXY_backup*.bak"
$FileNames = $server_files | select -ExpandProperty Name
$FileCheck = ('$Filenames ' + ($file_array | foreach {"-notlike '$_'"}) -join ' ')
Since you're already using wildcards in your file specs, this works with that by creating a command which filters the file name array through a series of -notlike operators, one for each file spec.
$FileCheck
$Filenames -notlike 'XXX_backup*.trn' -notlike 'XXX_backup*.bak' -notlike 'XXY_backup*.trn' -notlike 'XXY_backup*.bak'
Each one will filter out the names that match the file spec and pass the rest onto the next -notlike operator. Whatever falls out the end didn't match any of them
At this point $FileCheck is just a string, and you'll need to use Invoke-Expression to run it.
$ExtraFiles = Invoke-Expression $FileCheck
and then $ExtraFiles should contain the names of all the files that did not match any of the file specs in $file_array. Since the filters are being created from $file_array, there's no other maintenance to do if you add or remove filespecs from the array.

Resources