Office365 – How to Block Self Service Purchase Apps

December 5, 2019

Microsoft is enabling all O365 user to use self service Apps.

This means everyone on your tenant can start purchasing certain apps by default …

If you want disable this behaviour than you need to use PowerShell.

SOLUTION :

1. Download and install the PS MSCommerce Module

Install-Module -Name MSCommerce 

image

2. Next import the module and connect

Import-Module -Name MSCommerce

Connect-MSCommerce

image

3. Run these commands to see the status

Get-MSCommercePolicy -PolicyId AllowSelfServicePurchase 

Get-MSCommerceProductPolicies -PolicyId AllowSelfServicePurchase 

image

4. To disable 1 or all the products run this commands

Update-MSCommerceProductPolicy -PolicyId AllowSelfServicePurchase -ProductId CFQ7TTC0KP0P -Enabled $False  
Update-MSCommerceProductPolicy -PolicyId AllowSelfServicePurchase -ProductId CFQ7TTC0L3PB -Enabled $False  
Update-MSCommerceProductPolicy -PolicyId AllowSelfServicePurchase -ProductId CFQ7TTC0KP0N -Enabled $False 

5. To disable all in Batch run this command

Get-MSCommerceProductPolicies -PolicyId AllowSelfServicePurchase | `

Where { $_.PolicyValue -eq “Enabled”} | `

forEach { 

Update-MSCommerceProductPolicy -PolicyId AllowSelfServicePurchase -ProductId $_.ProductID -Enabled $false  }

image

You can check the status again :

image

Enjoy !


PowerShell – Monitor CPU Cores Temperatures

October 19, 2019

In order to Monitor the Temperature of your CPU Cores it is best to make use of OpenHardwareMonitorLib

 

image

You can download it here.

 

This nice application has a .Net Library that you can use to access the Hardware Sensors Data

It also exposes the values to WMI when the GUI is started, but that is not so convenient for monitoring

 

SOLUTION :

# Needs admin privileges and the .NET OpenHardwareMonitorLib.dll

#Requires -RunAsAdministrator

CLS

Add-Type -Path "C:\OpenHardwareMonitor\OpenHardwareMonitorLib.dll"

$Comp = New-Object -TypeName OpenHardwareMonitor.Hardware.Computer

$Comp.Open()

$Comp.CPUEnabled = $true

$Comp.RAMEnabled = $true

$Comp.MainboardEnabled = $true

$Comp.FanControllerEnabled = $true

$Comp.GPUEnabled = $true

$Comp.HDDEnabled = $true

ForEach ($HW in $Comp.Hardware) {

$HW.Update()
    $hw.HardwareType.ToString() + ' - ' + $hw.name.ToString()

    If ( $hw.HardwareType -eq "CPU"){
        ForEach ($Sensor in $HW.Sensors) {

        If ($Sensor.SensorType -eq "Temperature"){
            
            $Sensor.Name + ' - Temp : ' + $Sensor.Value.ToString() + ' C - Min. : ' + $Sensor.Min.ToString() + ' C - Max : ' + $Sensor.Max.ToString() + ' C'
        }
      }
    }
   
    # $hw.Sensors
    $hw.SubHardware
}
$Comp.Close()

 

image

 

If you add an Email Notifications when it reaches the MAX values, you have a nice Monitoring System Smile

Enjoy !


PowerShell – VBA Read Outlook Emails and Export to Excel

August 28, 2019

Getting data out of Outlook using a VBA or a COM Script is not that difficult.

But when you want to reach the data in a Shared Mailbox that’s a different story !

 

There are different options :

1. VBA script in Outlook export to clipboard

2. VBA script in Excel and export to a sheet

3. PS script that that can handle both Outlook and Excel sheet Export

 

SOLUTION :

Outlook Script that can export to a clipboard.

But it runs quite slow and is depending on Microsoft Forms Library.

That is not by default available, so you need reference it.

The COM Library located here C :\WINDOWS\SysWOW64\FM2O. DLL

 

image

 

Sub ListMailsInFolder()
    Dim clipboard As New MSForms.DataObject
    Set clipboard = New MSForms.DataObject
    Dim txt As String
        
    Dim objNS As Outlook.NameSpace
    Dim objFolder As Outlook.MAPIFolder
    Dim olShareName As Outlook.Recipient
    Dim MailItems As MailItem
    Dim FmtToday As String
    
    FmtToday = Format(Date - 1, "DDDDD HH:NN")
    Debug.Print DateValue(Now()) - 1
    
    Set objNS = GetNamespace("MAPI")
    Set olShareName = objNS.CreateRecipient("outbound@yourcompany.com")
    'Set objFolder = objNS.Folders.GetFirst ' folders of your current account
    
'Shared Inbox
    Set objFolder = objNS.GetSharedDefaultFolder(olShareName, olFolderInbox) '// Inbox
    Set Items = objFolder.Items.Restrict("[ReceivedTime] > '" & FmtToday & "'")
    
    Debug.Print Items.Count
    
    For Each MailItems In Items
        'If TypeName(Item) = "MailItem" Then
            ' ... do stuff here ...
            Debug.Print MailItems.Subject & " " & MailItems.ReceivedTime
        'End If
        
        'Put some text inside a string variable
        txt = txt & MailItems.Subject & " " & MailItems.ReceivedTime & vbNewLine

        'Sleep (500)
    Next
    
    'Make object's text equal above string variable
     clipboard.SetText txt
    
' SubFolder
    Set objFolder = objNS.GetSharedDefaultFolder(olShareName, olFolderInbox).Parent.Folders("Shipments")  '
    Set Items = objFolder.Items.Restrict("[ReceivedTime] > '" & FmtToday & "'")
    Debug.Print "[ReceivedTime] > '" & FmtToday & "'"
    
    Debug.Print Items.Count
    
    For Each MailItems In Items
        'If TypeName(Item) = "MailItem" Then
            ' ... do stuff here ...
            Debug.Print MailItems.Subject & " " & MailItems.ReceivedTime
        'End If
        
        'Put some text inside a string variable
        txt = txt & MailItems.Subject & " " & MailItems.ReceivedTime & vbNewLine
        
        'Sleep (500)
    Next

    'Make object's text equal above string variable
     clipboard.SetText txt

    'Place DataObject's text into the Clipboard
    clipboard.PutInClipboard
End Sub

 

Initially it ran very SLOW, so I optimized it for speed using the RESTRICT method FILTERING.

Which runs a lot FASTER. Smile

 

You can convert this an Excel Macro to EXPORT it to a workbook sheet.

I added a input box to select the date FROM and TO, as well as added a Calendar Control Winking smile

image

image

See here on how to add a Calendar Control

https://www.ablebits.com/office-addins-blog/2016/10/12/insert-calendar-excel-datepicker-template/

 

Option Explicit

Sub Button1_Click()
    On Error GoTo ErrHandler
    
    Columns("A:C").Select
    Selection.ClearContents
    
    Dim dStartDate As Date
    Dim dEndDate As Date

'Enter the specific start date and end date
    dStartDate = InputBox("Enter the start date, such as 7/1/201x:", "Specify Start Date", Range("F2").Value)
    dEndDate = InputBox("Enter the end date, such as 8/31/201x:", "Specify End Date", Date)

If dStartDate <> #1/1/4501# And dEndDate <> #1/1/4501# Then
    
' Set Outlook APPLICATION OBJECTS.
    Dim Outlook As Object
    Set Outlook = CreateObject("Outlook.Application")
    
    Dim clipboard As New MSForms.DataObject
    Dim txt As String
        
    Const olFolderInbox = 6
    Dim objNS As Object
    Dim Items As Object
    Dim Item As Object
    Dim objFolder As Outlook.MAPIFolder
    Dim olShareName As Outlook.Recipient
    
    
    Set objNS = GetNamespace("MAPI")
    Set olShareName = objNS.CreateRecipient("outbound@yourcompany.com")
    'Set objFolder = objNS.Folders.GetFirst ' folders of your current account
    
'Shared Mailbox Inbox
    Set objFolder = objNS.GetSharedDefaultFolder(olShareName, olFolderInbox) '// Inbox
    Set Items = objFolder.Items
    
    Set clipboard = New MSForms.DataObject
    
    Dim iRows, iCols As Integer
    iRows = 2
    
    For Each Item In objFolder.Items
        'If TypeName(Item) = "MailItem" Then
            ' ... do stuff here ...
            Debug.Print Item.Subject
        'End If
        
    'Put some text inside a string variable
        txt = txt & Item.Subject & vbNewLine
        
        If Format(Item.ReceivedTime, "dd/MM/YYYY") >= dStartDate And Format(Item.ReceivedTime, "dd/MM/YYYY") <= dEndDate Then
        Cells(iRows, 1) = Item.Subject
        Cells(iRows, 3) = Item.ReceivedTime
        iRows = iRows + 1
        End If
    Next
    
    'Make object's text equal above string variable
     clipboard.SetText txt
   
' Shared Mailbox SubFolder(s)
    Set objFolder = objNS.GetSharedDefaultFolder(olShareName, olFolderInbox).Parent.Folders("Shipments")
    '.Parent.Folders("Shipments").Folders("_ToDo") ' Subfolders
    Set Items = objFolder.Items
    
    For Each Item In objFolder.Items
        'If TypeName(Item) = "MailItem" Then
            ' ... do stuff here ...
            Debug.Print Item.Subject
        'End If
        
    'Put some text inside a string variable
        txt = txt & Item.Subject & vbNewLine
        
'Debug.Print Format(Item.ReceivedTime, "dd/MM/YYYY") & " - " & dStartDate

        If Format(Item.ReceivedTime, "dd/MM/YYYY") >= dStartDate And Format(Item.ReceivedTime, "dd/MM/YYYY") <= dEndDate Then
            Cells(iRows, 1) = Item.Subject
            Cells(iRows, 3) = Item.ReceivedTime
            iRows = iRows + 1
        End If
        Next

'Object's text to Clipboard
    clipboard.SetText txt

'Place DataObject's text into the Clipboard
    clipboard.PutInClipboard
   
' Release Objects
    Set Outlook = Nothing
    Set objNS = Nothing
    Set olShareName = Nothing
    Set clipboard = Nothing
    Set objFolder = Nothing
    Set Items = Nothing

End If

ErrHandler:
    Debug.Print Err.Description
End Sub

 

This is the PowerShell Version !

 

CLS

[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')

$title = "Start Date"
$msg   = "From"
$default   = (Get-Date).AddDays(-1).ToString("d")  # Get-Date -UFormat "%m/%d//%Y" or (Get-Date).AddDays(-1).ToString("MM/dd/yyyy")

$sDate = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title, $default)

[string]$sDate += "  00:00" # + (Get-Date).tostring(‘t’)


[threading.thread]::CurrentThread.CurrentCulture = 'en-US'  # Important line !!

$excel = New-Object -ComObject Excel.Application
$excel.Visible = $true
$workbook = $excel.Workbooks.Add()

$workbook.WorkSheets.Item(1).Name = "Outbound"

$sheet = $workbook.ActiveSheet

$olFolderInbox = 6

    Add-type -assembly “Microsoft.Office.Interop.Outlook” | out-null

    $outlook = new-object -comobject outlook.application


    $namespace = $outlook.GetNameSpace(“MAPI”)

    $olShareName =  $namespace.CreateRecipient("outbound@yourcompany.com")

    $olShareName.Resolved()

    $sFilter = ("[ReceivedTime] >= '$olddate'")

# Shared Inbox

    $Folder = $namespace.GetSharedDefaultFolder($olShareName, $olFolderInbox)
    
    $Items = $Folder.Items.Restrict("[ReceivedTime] > '$sDate'")
    
    $Items | Select-Object -Property Subject, ReceivedTime, SenderName, SenderEmailAddress | ? {$_ -match "@"} 


    # $Items | Export-CSV -NoTypeInformation XXXX\Trial.csv 

$counter = 0

    foreach($Item in $Items){

     $Email = ($Item.SenderEmailAddress | ? {$_ -match "@"})

   # ($Item.Subject + " " + $Item.ReceivedTime + " " + $Item.SenderName + " " + $Email)

    $counter++
        
        $sheet.cells.Item($counter,1) = $Item.Subject
        $sheet.cells.Item($counter,3) = $Item.ReceivedTime.Date
    }


# SubFolder
    $SubFolder = $Folder.Parent.Folders("Shipments")

    $olddate = (Get-Date).AddDays(-2).ToLongDateString()

    $Items = $SubFolder.Items.Restrict("[ReceivedTime] > '$sDate'")
    
    $Items | Select-Object -Property Subject, ReceivedTime, SenderName, SenderEmailAddress | ? {$_ -match "@"} 

    # $array | Export-CSV -NoTypeInformation XXXX\Trial.csv 

    foreach($Item in $Items){

    $Email = ($Item.SenderEmailAddress | ? {$_ -match "@"})

    # ($Item.Subject + " " + $Item.ReceivedTime + " " + $Item.SenderName + " " + $Email)

    $counter++
        
        $sheet.cells.Item($counter,1) = $Item.Subject
        $sheet.cells.Item($counter,3) = $Item.ReceivedTime.Date
    }
 
 $sheet.Cells.EntireColumn.AutoFit()


[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Outlook)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)

# Stop-Process -Name EXCEL -Force

Remove-Variable Excel, Email

 

Enjoy !!


PowerShell – How to run an EncodedCommand using a Bat file

August 23, 2019

If you don’t want to expose the PowerShell script logic to your end users,

you can use the EncodedCommand switch to run Base64 Encoded files.

 

Next if you don’t want to give the PowerShell command or PS IDE you can use just a Bat file instead.

 

But this is challenging to get it all working. Confused smile

 

SOLUTION :

1. Create a Bat file that calls the Encoded PowerShell script :

Like this …

 

Powershell -file "C:\TEMP\OUTBOUND_Logfiles.ps1"

 

image

Next create an EncodedCommand PowerShell script :

Like this …

powershell.exe -EncodedCommand "JABmAGkAbABlAHMAIAA9ACAARwBlAHQAL...."

 

TIP :

If you want to use the Out-GridView for showing the output in a GUI.

You will need to at this to the end of the script in order to keep the GridView Open at the end.

....

Read-Host "press enter to exit"

 

image

Otherwise the GridView will not remain open at the end when the script finished Smile

 

Enjoy !!


PowerShell – GUI Ribbon

July 5, 2019

Ever wanted to build a modern GUI including a Ribbon in just a few clicks …

Office 2007 Style

image

Office 2010 Style

image

Office 2013 Style

image

Well this is where it all starts :

New Site : https://github.com/RibbonWinForms/RibbonWinForms

Old Site : https://www.codeproject.com/Articles/364272/Easily-Add-a-Ribbon-into-a-WinForms-Application-Cs?fid=1704255&df=90&mpp=25&sort=Position&view=Normal&spc=Relaxed&fr=101&prof=True

Movie : https://www.youtube.com/watch?v=OPrj7c1CYIg

Since the documentation shows all C# code we can easily transform this a PowerShell Script Winking smile

PREREQUISITES :

You need to download here the Ribbon Assembly to reference in the script.

SOLUTION :

Don’t forget to change the path to the Assembly and the ICONS

Add-Type -Path "C:\_\System.Windows.Forms.Ribbon35.dll"

$form = New-Object System.Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(600,300)
$form.TopMost = $true
$form.StartPosition = "CenterScreen"

$form.AutoScalemode = "Font" # Enum Font or DPI
$form.AutoSize = $true
$form.AutoSizeMode = "GrowOnly"  # "GrowAndShrink"

$form.SuspendLayout()

# Objects
$ribbon = New-Object System.Windows.Forms.Ribbon
$tab1 = New-object System.Windows.Forms.RibbonTab
$tab2 = New-object System.Windows.Forms.RibbonTab
$MenuItem1 = New-object System.Windows.Forms.RibbonOrbMenuItem
$panel1 = New-object System.Windows.Forms.RibbonPanel
$button1 = New-object System.Windows.Forms.RibbonButton

# $ribbon | get-member
# $ribbon.Parent

# ribbon1
$ribbon.Font = New-Object System.Drawing.Font("Segoe UI", 9);
$ribbon.Location = New-Object System.Drawing.Point(0, 0);
$ribbon.Minimized = $false;
$ribbon.Name = "ribbon1";

$ribbon.OrbStyle = "Office_2007" # "Office_2010"
#$ribbon.Visible = $true

$ribbon.OrbDropDown.BorderRoundness = 8;
$ribbon.OrbDropDown.Location = New-Object System.Drawing.Point(0, 0);
$ribbon.OrbDropDown.MenuItems.Add($MenuItem1);
$ribbon.OrbDropDown.Name = "Drop";
$ribbon.OrbDropDown.Size = New-Object System.Drawing.Size(527, 116);
$ribbon.OrbDropDown.TabIndex = 0;
$ribbon.OrbImage = $null;
$ribbon.RibbonTabFont = New-Object System.Drawing.Font("Trebuchet MS", 9);
$ribbon.Size = New-Object System.Drawing.Size(1280, 200);
$ribbon.TabIndex = 0;
$ribbon.Tabs.Add($Tab1);
$ribbon.TabsMargin = New-Object System.Windows.Forms.Padding(12, 26, 20, 0);
$ribbon.Text = "ribbon1";
$ribbon.ThemeColor = "Blue";
$ribbon.Height = 150

# ribbonOrbMenuItem1
$MenuItem1.DropDownArrowDirection = "Left";
$MenuItem1.Image = [System.Drawing.Image]::FromFile("C:\_\ABF-Outlook.gif") 
# ((System.Drawing.Image)(resources.GetObject("ribbonOrbMenuItem1.Image")));
$MenuItem1.SmallImage = [System.Drawing.Image]::FromFile("C:\_\ABF-Outlook.gif") 
# ((System.Drawing.Image)(resources.GetObject("ribbonOrbMenuItem1.SmallImage")));
$MenuItem1.Text = "ribbonOrbMenuItem1";

# ribbonTab1
$Tab1.Panels.Add($panel1);
$Tab1.Text = "ribbonTab1";

# ribbonPanel1
$Panel1.Items.Add($Button1);
$Panel1.Text = "ribbonPanel1";

# ribbonButton1
$Button1.Image = [System.Drawing.Image]::FromFile("C:\_\SaveItem.png") 
#((System.Drawing.Image)(resources.GetObject("ribbonButton1.Image")));
$Button1.SmallImage = [System.Drawing.Image]::FromFile("C:\_\SaveItem.png") 
# ((System.Drawing.Image)(resources.GetObject("ribbonButton1.SmallImage")));
$Button1.Text = "ribbonButton1";

# ribbonTab2
$Tab2.Text = "ribbonTab2";

$form.Controls.Add($ribbon)

$form.ResumeLayout($false)

$form.ShowDialog()



image


image

Enjoy !




PowerShell – Report Designer Assembly in a .NET GUI

June 4, 2019

If you need a Report Designer that has all basic functionality needed.

And can connect to multiple Data Sources…

image

Print Preview

image

And more …

image

This is the way to go.

Prerequisites :

Download the Assembly from here 

(if you don’t find it there you can email the developer and he will send it over)

Save the Assembly somewhere locally.

SOLUTION :

This script will trigger the GUI that give you full functionality in PowerShell in less then 10 lines of code !

This is because PS can access .NET Assemblies Smile

CLS

Add-Type -AssemblyName System.Windows.Forms
Add-Type -Path "C:\_\Apps\_PowerShell\_GUI Forms\.NET Report Builder\MySql.Data.dll"
Add-Type -Path "C:\_\Apps\_PowerShell\_GUI Forms\.NET Report Builder\ReportDesigner5.dll"


$rd = New-Object ReportDesigner5.Designer


#$rd.Dock = [System.Windows.Forms.DockStyle]::Fill
$rd.ShowDialog()
$rd.ShowProperty()
$rd.ShowReportTree()

image

One TIP : Winking smile

– You also need to run it in PS x86 bit for the moment.

– You need to play around with the ZOOM scalar to get the report visible 

Alternatively you can as well download the EXE  here :

That has the same possibilities if you don’t want to use PS.

image

A new version was released on my request to add SQLite as a data source Smile

image

image

Keep in mind that you need to reference 2 additional Assemblies for this version :

1. QRCoder.dll version 1.3.5

2. SQLIte.dll version 1.0.109

Many thanks the to developer to create this nice Reporting tool and providing the Assembly !

Enjoy !


PowerShell – Retrieve a SSRS Report in a .NET GUI

May 5, 2019

Ever wanted to create you Offline Reporting Engine based on SSRS using PowerShell !

The objective is to run the RDL reports server side and display in .NET GUI client side.

PREREQUISITES :

You first need to download the .NET Assemblies using the SSRS redistributables.

Download here :

2008 / 2010 / 2012 or 2015 for a newer version see here

SOLUTION :

The solution is based on .Net Scripting in PowerShell using a GUI.

REMOTE processing mode :

CLS
# [System.Reflection.Assembly]::LoadWithPartialName(“Microsoft.ReportViewer.WinForms”)
Add-Type -Path "C:\WINDOWS\assembly\GAC_MSIL\Microsoft.ReportViewer.WinForms\12.0.0.0__89845dcd8080cc91\Microsoft.ReportViewer.WinForms.dll"

#Windows.Forms for viewing dialog box
# [void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
Add-Type -AssemblyName "System.Windows.Forms"

# for credentials, if needed
# [void][System.Reflection.Assembly]::LoadWithPartialName("System.Net")
Add-Type -AssemblyName System.Net

$credential = Get-Credential

$rv = New-Object Microsoft.Reporting.WinForms.ReportViewer;
$rv.ServerReport.ReportServerCredentials.NetworkCredentials = $credential

$rv.ProcessingMode = "Remote"

$rv.ServerReport.ReportServerUrl = "http://YourServer/Reportserver"
$rv.ServerReport.ReportPath = "/YourReportName”

$rv.Height = 600;
$rv.Width = 800;
$rv.RefreshReport();

#---------------------
# Show as Dialog Using Windows Form
#---------------------
# Create a new form
$form = New-Object Windows.Forms.Form;

# Form Properties
$form.Height = 610;
$form.Width= 810;
$form.Controls.Add($rv);
$rv.Show();
$form.ShowDialog();

#---------------------
# Export to Excel
#---------------------
#now let’s try exporting to Excel
$mimeType = $null;
$encoding = $null;
$extension = $null;
$streamids = $null;
$warnings = $null;

$bytes = $rv.ServerReport.Render("Excel”, $null,
[ref] $mimeType,
[ref] $encoding,
[ref] $extension,
[ref] $streamids,
[ref] $warnings);
$file = "C:\Temp\SampleReport.xls”;
$fileStream = New-Object System.IO.FileStream($file,
[System.IO.FileMode]::OpenOrCreate);
$fileStream.Write($bytes, 0, $bytes.Length);
$fileStream.Close();

#l Open up our excel application
$excel = New-Object -comObject Excel.Application
$excel.visible = $true;
$excel.Workbooks.Open($file) | Out-Null;

#---------------------
# Export to PDF
#---------------------
$bytes = $rv.ServerReport.Render("PDF”, $null,
[ref] $mimeType,
[ref] $encoding,
[ref] $extension,
[ref] $streamids,
[ref] $warnings);
$file2 = "C:\Temp\SampleReport.pdf”;
$fileStream = New-Object System.IO.FileStream($file2,
[System.IO.FileMode]::OpenOrCreate);
$fileStream.Write($bytes, 0, $bytes.Length);
$fileStream.Close();
[System.Diagnostics.Process]::Start($file2)
image

The result is the report in your own GUI that runs locally and is processed centrally, when you use REMOTE

If the report has Parameters it will prompt you to enter them just like in the Web Form.

image

After the GUI is close the script will be EXPORT the content to EXCEL and PDF too.

You will have the options to EXPORT to all supported formats, or add your own extension if you are working server side.

image

LOCAL processing mode :

Most interesting is that you can run the Report Viewer Control in LOCAL processing mode !

Which means that you can create a Local Reporting Engine that runs the RDL reports from you client in a PowerShell GUI

image

And additionally you can add any kind of .Net support Data Source, like in this case an SQLite database !

Which is not supported by server side SSRS…

How cool is that ! Surprised smile

For more info see here

Happy Scripting Smile

Enjoy!