Powershell - Reading CSV File as Individual Lines - powershell

I have this powershell script to get some email counts which works fine if I only have one user in the csv file but when I put two or more it reads it all as one line and then I get an invalid SMTP address error. I can't for the life of me figure out how to get it to read each line individually. Could someone take a look at this powershell script and help me out?
############ Start Import the Exchange 2010 modules if available, otherwise import 2007.
if (Get-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -Registered -ErrorAction SilentlyContinue) {
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
} else {
Add-PSSnapin -Name Microsoft.Exchange.Management.PowerShell.Admin
}
############ Start Variables
[Int] $intSent = $intRec = 0
$emails = Get-Content "C:\Test.csv"
$dt = (get-date).adddays(-1)
$tab2 = #()
$tabInfo = #()
############ End variables
############ Start HTML Style
$head = #'
<style>
body { background-color:#FFFFFF;
font-family:Tahoma;
font-size:11pt; }
td, th { border:1px solid black;
border-collapse:collapse;
text-align:center;
background+color:#e0e0e0;
width:300px;}
th { color:#ffffff;
background-color:#20a000;
text-align:center;}
table, tr, td, th { padding: 1px; margin: 0px }
table { margin-left:15px; }
</style>
'#
############ End HTML Style
############ Start retrieve email address + NB sent/received mails
foreach ($i in $emails) {
$intRec = 0 #Number of received mails
$intSent = 0 #Number of sent mails
$intTotalSentInt = 0 #Number of sent internal mails
$intTotalSentExt = 0 #Number of sent external mails
$intTotalRecInt = 0 #Number of received internal mails
$intTotalRecExt = 0 #Number of received external mails
$address = $emails #Email address
$object = new-object Psobject #Create the object
$objectInfo = new-object Psobject #Create the object info
############ Sent mails
Get-TransportService | Get-MessageTrackingLog -ResultSize Unlimited -Start $dt -Sender $emails -EventID RECEIVE | ? {$_.Source -eq "STOREDRIVER"} | ForEach {
If ($_.Recipients -match "domain.com") {
$intTotalSentInt++
}
If ($_.Recipients -notmatch "domain.com") {
$intTotalSentExt++
}
}
############ Received mails
Get-TransportService | Get-MessageTrackingLog -ResultSize Unlimited -Start $dt -Recipients $emails -EventID DELIVER | ForEach {
If ($_.Sender -match "domain.com") {
$intTotalRecInt += [Int] $_.RecipientCount
} Else {
# From an external sender
$intTotalRecExt += [Int] $_.RecipientCount
}
}
############ Insert address + number of sent/received mails
$object | Add-member -Name "User" -Membertype "Noteproperty" -Value $emails
$object | Add-member -Name "Internal Emails Sent" -Membertype "Noteproperty" -Value $IntTotalSentInt
$object | Add-member -Name "External Emails Sent" -Membertype "Noteproperty" -Value $IntTotalSentExt
$object | Add-member -Name "Internal Emails Received" -Membertype "Noteproperty" -Value $intTotalRecInt
$object | Add-member -Name "External Emails Received" -Membertype "Noteproperty" -Value $intTotalRecExt
$tab2 += $object
}
############ Sort by number of sent emails
$tab2 = $tab2 | Sort-Object Sent -descending
############ ConvertTo-HTML
$body = $tabInfo | ConvertTo-HTML -head $head
$body += $tab2 | ConvertTo-HTML -head $head
############ Send emails with results
send-mailmessage -to "email#domain.com" -from "email#domain.com" -subject "Emails Sent and Received from $dt" -body ($body | out-string) -BodyAsHTML -SmtpServer "x.x.x.x"
############ end of Script
Sample CSV file that just contains email addresses

Line 45, inside the foreach ($i in $emails), you're doing $address = $emails which puts the entire list of emails in $address. I assume you meant $address = $i ?
Edit: and I missed the one which is probably the problematic one, line 50, you're passing $emails which is an array whereas -Sender takes a string.

Related

Update PowerShell Script to Check Remote Services

I am working on a server validation script that runs via PowerShell, and reaches out to collect remote machine information (pulls the list of servers from a text file), such as server uptime and pending reboot. It takes the information, places it in a CSV file and posts it to a HTML (Results) document.
My ask: I'm trying to reach out to these servers (contained on the .txt file) to validate that certain services are in the running state, and if they are, post the status as 'Running' and if not (else), post as 'Not Running'.
Example of getting the list of servers:
$title = 'Important! Please Read'
$message = 'Is this validation going to run against production servers?'
$choice = #(
[System.Management.Automation.Host.ChoiceDescription]::new(
'&Yes', 'This will execute against Production servers' # => This is help message
)
[System.Management.Automation.Host.ChoiceDescription]::new(
'&No', 'This will execute against Non-Production servers' # => This is help message
)
)
$defaultCoice = 0 # => No
$userinput = $host.UI.PromptForChoice($title, $message, $choice, $defaultCoice)
$prodserverlist = if($userinput -eq 0) {
Get-Content '\\networkshare\PostPatchingValidation\ServerListProd.txt'
}
else {
Get-Content '\\networkshare\PostPatchingValidation\ServerListDev.txt'
}
Example of Check Uptime:
Function Uptime($comp){
function WMIDateStringToDate($Bootup) {
[System.Management.ManagementDateTimeconverter]::ToDateTime($Bootup)
}
$NameSpace = "Root\CIMV2"
$wmi = [WMISearcher]""
$wmi.options.timeout = '0:0:10' #set timeout to 10 seconds
$query = 'Select * from Win32_OperatingSystem'
$wmi.scope.path = "\\$comp\$NameSpace"
$wmi.query = $query
Try{
$wmiresult = $wmi.Get()
#$wmiresult
foreach ($wmioutput in $wmiresult){
$Bootup = $wmioutput.LastBootUpTime
$LastBootUpTime = WMIDateStringToDate($Bootup)
$now = Get-Date
$Reporttime = $now - $lastBootUpTime
$d = $Reporttime.Days
$h = $Reporttime.Hours
$m = $Reporttime.Minutes
$a = "Up for: {0} Days, {1} Hours, {2:N0} Minutes" -f $d,$h,$m
return $a
}
}
Example of Posting results to CSV:
foreach($comp in $prodserverlist){
$i++
$ErrorActionPreference = "SilentlyContinue"
Write-Progress -Activity "Server Health Check " -Status ("Checking Server : {0}" -f $comp) -PercentComplete ($i/$prodserverlist.count*100) -Id 0
$ErrorActionPreference = "Continue"
#region Var_Nulling :p
$autoservices= $null
$Reporttimestatus = $null
$service = $null;
$services = $null;
$totalfailednew = $null
#endregion
$Reporttimestatus = uptime -comp $comp
# $services = Get-Service -comp $comp
$pd = PendingReboot $comp
$newobj = $null
$newobj = new-object psobject
$newobj | add-member -membertype noteproperty -name "Server" -value $comp
$newobj | add-member -membertype noteproperty -name "Uptime" -value $Reporttimestatus #-PassThru
$newobj | add-member -membertype noteproperty -name "PendingReboot" -value $pd
$newobj | add-member -membertype noteproperty -name "ServiceCheck" -value $Reporttimestatus
$newobj | ConvertTo-Csv -NoTypeInformation | Out-File "\\networkshare\PostPatchingValidation\result.csv" -Append
$htmlserver = $newobj.Server
$htmluptime = $newobj.Uptime
$htmlpendingreboot = $newobj.PendingReboot
$htmlservicecheck = $newobj.ServiceCheck
$current = "
<tr bgcolor=#CCCCCC>
<td width='14%' align='center'>$htmlserver</td>
<td width='23%' align='center'>$htmluptime</td>
<td width='12%' align='center'>$htmlpendingreboot</td>
<td width='12%' align='center'></td>
</tr>
"
$total += $current
#$newobj | ConvertTo-html -Fragment
#$newobj | ConvertTo-html -Fragment -CssUri \\networkshare\PostPatchingValidation\Style.css | Out-File \\networkshare\PostPatchingValidation\result.html -Append
}
$HTMLEnd = #"
</div>
</body>
</html>
"#
$MainHtml= $html + $total + $HTMLEnd
$MainHtml | Out-File "\\networkshare\PostPatchingValidation\result.html"
Final Screenshot of HTML Document:

Export Eventlogs and send email

I have written a script to export specific Eventvwr logs based on Source and the script is working as expected, but i am trying to cut short the message form the Eventvwr, i dont to print entire message on the mail.
I am attaching the output of my code below
#
# This script exports consolidated and filtered event logs to CSV
#
#Application error and critical eventlogs for specific EventID:
#Email Details
$FromAddress = 'abc.com'
$ToAddress = '123.com'
$SmtpServer = 'xyz.com'
Set-Variable -Name EventAgeDays -Value 4 #we will take events for the latest 7 days
Set-Variable -Name CompArr -Value #("abcedf.com") # replace it with your server names
Set-Variable -Name LogNames -Value #("Application") # Checking app and system logs
Set-Variable -Name EventTypes -Value #("Information") # Loading only Errors and Warnings
Set-Variable -Name ExportFolder -Value "C:\xxx\"
Set-Variable -Name Source -Value #("123", "111")
$el_c = #() #consolidated error log
$now=get-date
$startdate=$now.adddays(-$EventAgeDays)
$ExportFile=$ExportFolder + "Out" + $now.ToString("yyyy-MM-dd---hh-mm-ss") + ".csv" # we cannot use standard delimiteds like ":"
foreach($comp in $CompArr)
{
foreach($log in $LogNames)
{
foreach ($src in $Source)
{
Write-Host Processing $comp\$log
$el = get-eventlog -ComputerName $comp -log $log -After $startdate -EntryType $EventTypes -Source $src -Newest 1 -InstanceId 30000
$el_c += $el #consolidating
#}
#}
$el_sorted = $el_c | Sort-Object TimeGenerated #sort by time
Write-Host Exporting to $ExportFile
}
}
}
$out = $el_sorted|Select MachineName, EntryType, TimeGenerated, Source, EventID, Message #| Export-CSV $ExportFile -NoTypeInfo #EXPORT
Write-Host Done!
$msgBody = $out
Send-MailMessage -from $FromAddress -to $ToAddress -SmtpServer $SmtpServer -Subject "TL Stage Ingester Status from $CompArr $startdate" -Body ( $msgBody | Out-String)

How to read input through a csv file and write the output in an output file in power shell script?

[This is the powershell script to get the selected services status of servers,where list of servers are given through input csv file and the status of those server should be stored in an output file.
-----------Below is the script----------
$Servers = Get-Content "C:\temp\input.csv"
$Log = #()
foreach($Server in $Servers)
{
$Services = Get-Service *HRRA*, "SQL Server Reporting Services" -ComputerName $COMPUTERNAME
foreach ($Service in $Services)
{
$properties = #(
#{n='ServiceName';e={$Service.Name}}
#{n='Status';e={$Service.Status}}
#{n='ServerName';e={$Server}}
)
$Log += "" | select $properties
}
}
$Log | Format-Table -AutoSize | Out-File "D:\temp\test.txt" -Force
------------------------------------New Script----------------------------------
$Computers = Import-Csv "C:\Temp\Input.csv"
#$mailboxdata = Get-Service *HRRA*,"SQL Server Reporting Services" -ComputerName $ComputerName| select machinename,name, status | sort machinename |
#format-table -AutoSize |Out-File "D:\Temp\RRR.txt"
#LogWrite "$ComputerName"
foreach($row in $computers)
{
{
Add-Content -Path D:\Temp\SSRS.txt -Value $mailboxdata }
Get-Content -Path D:\Temp\SSRS.txt
$ComputerName= $row.ComputerName;
$mailboxdata = Get-Service *HRRA*,"SQL Server Reporting Services" -ComputerName $ComputerName| select machinename,name, status | sort machinename |
format-table -AutoSize |Out-File "D:\Temp\SSR.txt"
$fromaddress = "Reporting.Services#accenture.com"
$toaddress = "aditi.m.singh#accenture.Com"
#$toaddress1 = "s.ab.balakrishnan#accenture.com"
$Subject = "SSRS Services Status"
$body = "Please find attached - test"
$attachment = "D:\Temp\SSR.txt"
$smtpserver = "AMRINT.SMTP.ACCENTURE.COM"
$message = new-object System.Net.Mail.MailMessage
$message.From = $fromaddress
$message.To.Add($toaddress)
#$message.To.Add($toaddress1)
$message.IsBodyHtml = $True
$message.Subject = $Subject
$attach = new-object Net.Mail.Attachment($attachment)
$message.Attachments.Add($attach)
$message.body = $body
$smtp = new-object Net.Mail.SmtpClient($smtpserver)
$smtp.Send($message)
}
If i am running the script with static value its giving me output for both the servers---Below is the script----
Get-Service *HRRA*,"SQL Server Reporting Services" -ComputerName VW118627, VW118623 | select name, status, machinename | sort machinename | format-table -AutoSize |
Out-File "D:\Temp\Report.txt"
Looking at the screenshot, I can see the input csv is really a Comma Separated Values file. For these, you use the Import-Csv cmdlet to retrieve an array of computer names from the file.
$outputFile = "D:\temp\test.csv"
# make sure the field name matches what is in the CSV header
$Servers = (Import-Csv -Path "C:\temp\input.csv").ComputerName
$Log = foreach($Server in $Servers) {
# add a test to see if we can reach the server
if (Test-Connection -ComputerName $Server -Count 1 -Quiet -ErrorAction SilentlyContinue) {
Get-Service -Name *HRRA*, "SQL Server Reporting Services" -ComputerName $Server |
Select-Object #{Name = 'MachineName'; Expression = {$Server}},
#{Name = 'ServiceName'; Expression = {$_.Name}},
#{Name = 'Status'; Expression = {$_.Status}}
}
else {
Write-Warning "Server '$Server' is unreachable"
}
}
# if you want the log sorted, do
$Log = $Log | Sort-Object MachineName
# output on screen
$Log | Format-Table -AutoSize
# output to CSV file
$Log | Export-Csv -Path $outputFile -Force -NoTypeInformation
# mail the output csv file using Send-MailMessage
# collect the parameters in a hashtable
$mailParams = #{
SmtpServer = "AMRINT.SMTP.ACCENTURE.COM"
From = "Reporting.Services#accenture.com"
To = "aditi.m.singh#accenture.com"
Subject = "SSRS Services Status"
Body = "Please find attached - test"
BodyAsHtml = $true
Attachments = $outputFile
# add other parameters if needed
# see https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/send-mailmessage
}
# use 'splatting' to send the email
# see https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_splatting
Send-MailMessage #mailParams
P.S. The Format-Table cmdlet is for displaying the object(s) on screen only.

Send-MailMessage, state never when LastLogonDate = never?

Using the ps below I'm emailing specific personnel certain AD account properties including LastLogonDate. If the account was never used the email omits the value entirely. I'd like the message to include something like the following:
John Smith logged onto our systems a total of 0 times with the last successful log in posted on N/A.
How can I modify what I have to accomplish this? Thanks!
# List every active account with a "SACRequest Account" desctription that will expire in 0,7,14 days and inlcude the name and email address of the original account requester (extensionAttribute1,extensionAttribute2)
import-module activedirectory
$Today = Get-Date -Format 'MM-dd-yyy'
$Rightnow = Get-Date -Format o
$reportObject = #()
$userList = get-aduser -filter {Description -like "SACRequest Account" -and Enabled -eq $True} -Properties displayname, accountExpires, description, passwordexpired,"msDS-UserPasswordExpiryTimeComputed",enabled,AccountExpirationDate,LastLogonDate,logoncount,passwordlastset, badlogoncount,lastbadpasswordattempt,extensionAttribute1,extensionAttribute2,department |
select displayname, accountExpires, description, passwordexpired,"msDS-UserPasswordExpiryTimeComputed",enabled,AccountExpirationDate,LastLogonDate,logoncount,passwordlastset, badlogoncount,lastbadpasswordattempt,extensionAttribute1,extensionAttribute2,department |
sort-object msDS-UserPasswordExpiryTimeComputed -descending
$obj = new-object PSobject
foreach ($user in $userList)
{
$obj = new-object PSobject
$obj | add-member noteproperty Name($user.displayname)
$obj | add-member noteproperty Description($user.description)
$obj | add-member noteproperty 'Password Expired'($user.Passwordexpired)
$obj | add-member noteproperty 'Account is Enabled'($user.Enabled)
$obj | add-member noteproperty 'AccountExpirationDate'($user.AccountExpirationDate.ToString('MM-dd-yyyy'))
$obj | add-member noteproperty 'LastLogonDate'($user.LastLogonDate.ToString('MM-dd-yyyy'))
$obj | add-member noteproperty 'Password Last Set'($user.PasswordLastSet)
$obj | add-member noteproperty 'Failed Logon Attempt'($user.lastbadpasswordattempt)
$obj | add-member noteproperty 'TotalLogonCount'($user.logoncount)
$obj | add-member noteproperty 'Total Failed Logons'($user.badlogoncount)
$obj | add-member noteproperty 'SACSubmitter'($user.extensionAttribute1)
$obj | add-member noteproperty 'SACSubmitterEmail'($user.extensionAttribute2)
$obj | add-member noteproperty 'Department'($user.department)
$reportObject += $obj}
$from = "System Access Control <systems#organization.org>"
foreach ($user in $reportObject) {
if (([datetime]$user.AccountExpirationDate).AddDays(-0) -eq $TodayOnly)
{
$Name = $user.name
$to = $user.SACSubmitterEmail
$subject = "Your contractors's login account will expire today!"
$hello = $user.SACSubmitter
$AccountExpirationDate = $user.AccountExpirationDate # -as [datetime]
$TotalLogonCount = $user.TotalLogonCount
$LastLogonDate = $user.LastLogonDate
$body = "Hello $hello,<br><br>"
$body += "The login account you requested for <b>$Name</b> will expire in one week on <b> $AccountExpirationDate</b>.<br><br>"
$body += "$name logged onto our systems a total of <b>$TotalLogonCount</b> times with the last successful log in posted on <b> $LastLogonDate</b>.<br><br>"
$body += "<a href='http://intranet/form.cfm?id=100'>If this account needs to remain active please submit a new System Access Control Request by clicking here.</a><br><br>"
$body += "Kind Regards,<br>"
$body += "Your friends in IT<br><br><br>"
$body += "<i>Data generated $RightNow</i>"
$mail = New-Object System.Net.Mail.Mailmessage $from, $to, $subject, $body
$mail.IsBodyHTML=$true
$server = "mail.organization.org"
$port = 25
$Smtp = New-Object System.Net.Mail.SMTPClient $server,$port
$Smtp.Credentials = [system.Net.CredentialCache]::DefaultNetworkCredentials
$smtp.send($mail)
}
}
foreach ($user in $reportObject) {
if (([datetime]$user.AccountExpirationDate).AddDays(-7) -eq $TodayOnly)
{
$Name = $user.name
$to = $user.SACSubmitterEmail
$subject = "Your contractors's login account will expire in one week!"
$hello = $user.SACSubmitter
$AccountExpirationDate = $user.AccountExpirationDate # -as [datetime]
$TotalLogonCount = $user.TotalLogonCount
$LastLogonDate = $user.LastLogonDate
$body = "Hello $hello,<br><br>"
$body += "The login account you requested for <b>$Name</b> will expire in one week on <b> $AccountExpirationDate</b>.<br><br>"
$body += "$name logged onto our systems a total of <b>$TotalLogonCount</b> times with the last successful log in posted on <b> $LastLogonDate</b>.<br><br>"
$body += "<a href='http://intranet/form.cfm?id=100'>If this account needs to remain active please submit a new System Access Control Request by clicking here.</a><br><br>"
$body += "Kind Regards,<br>"
$body += "Your friends in IT<br><br><br>"
$body += "<i>Data generated $RightNow</i>"
$mail = New-Object System.Net.Mail.Mailmessage $from, $to, $subject, $body
$mail.IsBodyHTML=$true
$server = "mail.organization.org"
$port = 25
$Smtp = New-Object System.Net.Mail.SMTPClient $server,$port
$Smtp.Credentials = [system.Net.CredentialCache]::DefaultNetworkCredentials
$smtp.send($mail)
}
}
foreach ($user in $reportObject) {
if (([datetime]$user.AccountExpirationDate).AddDays(-14) -eq $TodayOnly)
{
$Name = $user.name
$to = $user.SACSubmitterEmail
$subject = "Your contractors's login account will expire in two weeks!"
$hello = $user.SACSubmitter
$AccountExpirationDate = $user.AccountExpirationDate # -as [datetime]
$TotalLogonCount = $user.TotalLogonCount
$LastLogonDate = $user.LastLogonDate
$body = "Hello $hello,<br><br>"
$body += "The login account you requested for <b>$Name</b> will expire in one week on <b> $AccountExpirationDate</b>.<br><br>"
$body += "$name logged onto our systems a total of <b>$TotalLogonCount</b> times with the last successful log in posted on <b> $LastLogonDate</b>.<br><br>"
$body += "<a href='http://intranet/form.cfm?id=100'>If this account needs to remain active please submit a new System Access Control Request by clicking here.</a><br><br>"
$body += "Kind Regards,<br>"
$body += "Your friends in IT<br><br><br>"
$body += "<i>Data generated $RightNow</i>"
$mail = New-Object System.Net.Mail.Mailmessage $from, $to, $subject, $body
$mail.IsBodyHTML=$true
$server = "mail.organization.org"
$port = 25
$Smtp = New-Object System.Net.Mail.SMTPClient $server,$port
$Smtp.Credentials = [system.Net.CredentialCache]::DefaultNetworkCredentials
$smtp.send($mail)
}
}
Are you looking for something like
if ($user.LastLogonDate){
#$user.LastLogonDate is not null, use the value
$obj | add-member noteproperty 'LastLogonDate'($user.LastLogonDate.ToString('MM-dd-yyyy'))
} else {
#$user.LastLogonDate is null, use never
$obj | add-member noteproperty 'LastLogonDate' 'Never'
}
1.) remove this first PSobject, it's not needed. replace with step 2
$obj = new-object PSobject
foreach ($user in $userList)
{
2.) split off the 0day users from the user list
$0dayUsers = $userList |Where-Object {$_.LastLogonDate -like ''}
3.) remove 0day users from the original list
$userList = $userList |Where-Object {$_.LastLogonDate -notlike ''}
3.) add this below your 14 day contractor notice at the bottom, I've padded around the one change. I've left it up to you on how to tailor the sample to your target audience
foreach ($user in $0dayUsers) {
$Name = $user.name
$to = $user.SACSubmitterEmail
$subject = "Notice regarding orphaned account!"
$hello = $user.SACSubmitter
$AccountExpirationDate = $user.AccountExpirationDate # -as [datetime]
$TotalLogonCount = $user.TotalLogonCount
$LastLogonDate = $user.LastLogonDate
$body = "Hello $hello,<br><br>"
$body += "The login account you requested for <b>$Name</b> will expire in one week on <b> $AccountExpirationDate</b>.<br><br>"
$body += "$name logged onto our systems a total of <b>$TotalLogonCount</b> times with the last successful log in posted on <b> </b>.<br><br>"
$body += "<a href='http://intranet/form.cfm?id=100'>If this account needs to remain active please submit a new System Access Control Request by clicking here.</a><br><br>"
$body += "Kind Regards,<br>"
$body += "Your friends in IT<br><br><br>"
$body += "<i>Data generated $RightNow</i>"
$mail = New-Object System.Net.Mail.Mailmessage $from, $to, $subject, $body
$mail.IsBodyHTML=$true
$server = "mail.organization.org"
$port = 25
$Smtp = New-Object System.Net.Mail.SMTPClient $server,$port
$Smtp.Credentials = [system.Net.CredentialCache]::DefaultNetworkCredentials
$smtp.send($mail)
}
### The single curly brace is intentional, the if statement was removed since Select-Object already handled it.

O365 PowerShell Pull SubLicense

I am trying to pull a list of all users in my O365 Tenant and if they are licensed, the list of sublicenses they have been granted. The following code works great to list out my sublicenses:
$userlicensetest = get-msoluser -userprincipalname "steve.dorr#merrillcorp.com"
$userlicensetest.licenses[0].servicestatus
ServicePlan :: ProvisioningStatus
----------- :: ------------------
INTUNE_O365 :: PendingActivation
YAMMER_ENTERPRISE :: PendingInput
OFFICESUBSCRIPTION :: Success
So I tried to modify code I found online to include the sublicense information. Here is what I have built so far:
$ReportPath = "c:\users\userlist.csv"
Add-Content -value ("UserPrincipalName"+","+"IsLicensed"+","+ "Licenses”"+","+ "SubLicenses") -Path $ReportPath
$AllUsers = Get-MsolUser -All
foreach ($User in $AllUsers)
{
$UserPrincipalName = $User.UserPrincipalName
$IsLicensed = $User.IsLicensed
$Licenses = $User.Licenses.AccountSkuId
$SubLicenses = $User.Licenses[0].servicestatus
Add-Content -value ($UserPrincipalName+","+$IsLicensed+","+$Licenses+","+$SubLicenses) -Path $ReportPath
}
The problem is it is only pulling the header line from the sublicense query and not all the lines of detail. So the line for myself in the CSV looks like:
Steve.Dorr#MerrillCorp.com TRUE mymerrillcorp:ENTERPRISEPACK Microsoft.Online.Administration.ServiceStatus Microsoft.Online.Administration.ServiceStatus Microsoft.Online.Administration.ServiceStatus Microsoft.Online.Administration.ServiceStatus Microsoft.Online.Administration.ServiceStatus Microsoft.Online.Administration.ServiceStatus Microsoft.Online.Administration.ServiceStatus Microsoft.Online.Administration.ServiceStatus
Which does not give me the detail lines I needed.
How do I pull all the lines that Licenses[0].servicestatus generates into the CSV file? I don't care whether it flattens it out and goes across more columns, or takes up multiple lines in Excel.
Thanks.
So since I posted this question I have worked a little on it. I do not have a perfect solution that puts this into a nice neat CSV file, but I do have a routine which now drops all this information into a text file. Below is my code.
$MyCredentials = Get-Credential -Message "Enter Office 365 Email & Password"
Connect-MsolService -Credential $MyCredentials
$ReportFile = "C:\temp\O365Data.txt"
" " | Out-File $ReportFile #erases the file if it exists
$AllUsers = Get-MsolUser -All
foreach ($User in $AllUsers)
{
$UserPrincipalName = $User.UserPrincipalName
$IsLicensed = $User.IsLicensed
$Licenses = $User.Licenses.AccountSkuId
$SubLicenses = $User.Licenses[0].servicestatus
$OneLine = $UserPrincipalName + " " + $IsLicensed
$OneLine| Out-File $ReportFile -Append
if($User.Licenses[0].servicestatus) {$User.Licenses[0].servicestatus | Out-File $ReportFile -Append}
}
To create the report you'll need to create custom objects to hold the properties you are interested in.
The following will take into account all the different licenses that could be applied to a user and then generate a csv with one user listed per line.
# Connect to o365
$MyCredentials = Get-Credential -Message "Enter Office 365 Email & Password"
Connect-MsolService -Credential $MyCredentials
# Prepare result file
$ExportFile = ".\o365Output.csv"
Remove-Item $ExportFile
$Result = #()
# Query all Msol Users
$AllUsers = Get-MsolUser -All
foreach ($User in $AllUsers)
{
# Generate a new object for each user
$ReturnObject = [pscustomobject]#{
UserPrincipalName = $User.UserPrincipalName
IsLicensed = $User.IsLicensed
Licenses = [string]$User.Licenses.AccountSkuId
}
# In the event multiple licenses are found append properties for each license
foreach ($License in $User.Licenses)
{
if($($License.ServiceStatus.ServicePlan.ServiceName).count -eq 1)
{
$ReturnObject | Add-Member -MemberType NoteProperty -Name $License.ServiceStatus.ServicePlan.ServiceName -Value $License.ServiceStatus.ProvisioningStatus
}
else
{
for($i = 0; $i -lt $($License.ServiceStatus.ServicePlan.ServiceName).count; $i++)
{
$ReturnObject | Add-Member -MemberType NoteProperty -Name $License.ServiceStatus.ServicePlan.ServiceName[$i] -Value $License.ServiceStatus.ProvisioningStatus[$i]
}
}
}
$Result += $ReturnObject
}
# Combine properties from all returned objects
$Properties = $Result | ForEach-Object { Get-Member -InputObject $_ -MemberType NoteProperty | Select-Object -ExpandProperty Name } | Select-Object -Unique | Sort-Object
$Headers = #("UserPrincipalName")
$Headers += $Properties -notlike "UserPrincipalName"
# Export to csv
$Result | Select-Object $Headers | Export-Csv -NoTypeInformation $ExportFile
# Open csv
Invoke-Item $ExportFile