Compare commits
21 Commits
Powershell
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f1f67db3e4 | |||
| f0644294ee | |||
| c3cc6eb225 | |||
| 70a93d54b2 | |||
| daec2070d8 | |||
| 5f4f0a9808 | |||
| 2b1d775158 | |||
| 1833c48409 | |||
| b2469e962e | |||
| cafd06592f | |||
| dcf5428010 | |||
| 9779a35c98 | |||
| 605b2efbdc | |||
| 9e32e58cc0 | |||
|
|
80a3c501be | ||
|
|
3c467462e8 | ||
|
|
e326cd97c0 | ||
|
|
cfddd4fad2 | ||
|
|
f2475a3bdd | ||
|
|
b42ccc43b6 | ||
|
|
294eeba581 |
BIN
Powershell/Data/Abbr/.computer.csv.swp
Normal file
BIN
Powershell/Data/Abbr/.computer.csv.swp
Normal file
Binary file not shown.
50
Powershell/Data/Abbr/aviation.csv
Normal file
50
Powershell/Data/Abbr/aviation.csv
Normal file
@@ -0,0 +1,50 @@
|
||||
Abbreviation,Definition
|
||||
AB,Air Base
|
||||
AC,Aircraft
|
||||
ACAS,Airborne Collision Avoidance System
|
||||
ACC,Area Control Centre
|
||||
AF,Air Field
|
||||
AFM,Aircraft Flight Manual
|
||||
AIP,Aeronautical Information Publication
|
||||
AMAN,Arrival Manager
|
||||
AOA,Angle of Attack
|
||||
AOM,Airplane Operating Manual
|
||||
AOR,Area of Responsibility
|
||||
AFIS,Aerodrome Flight Information Service
|
||||
AFM,Airplane Flight Manual
|
||||
AGL,Above Ground Level
|
||||
AIP,Aeronautical Information Publication
|
||||
ANSP,Air Navigation Service Provider
|
||||
ARTCC,Air Route Traffic Control Centre
|
||||
ASB,Airspace Block
|
||||
ATA,Actual Time of Arrival
|
||||
ATC,Air Traffic Control
|
||||
ATIS,Automatic Terminal Information Service
|
||||
ATO,Air Traffic Organization
|
||||
BAF,Belgian Air Force
|
||||
CAAC,Civil Aviation Administration of China
|
||||
CAAS,Civil Aviation Authorization of Singapore
|
||||
CANSO,Civil Air Navigation Services Organization
|
||||
CAS,Calibrated Airspeed
|
||||
CAT,Category of Aircraft
|
||||
CAVOK,Ceiling And Visibility OK
|
||||
COG,Center of Gravity
|
||||
CRDA,Converging Runway Display Aid
|
||||
CTA,Controlled Time of Arrival
|
||||
CTA,Controlled Area
|
||||
CTOT,Calculated Take-Off Time
|
||||
CTR,Control Zone or Controlled Traffic Region
|
||||
ECAC,European Civil Aviation Conference
|
||||
FIA,Flight Information Area
|
||||
FIR,Flight Information Region
|
||||
FL,Flight Level
|
||||
IAS,Indicated Air Speed
|
||||
LL,Lower Limit
|
||||
LTA,Lower Traffic Area
|
||||
MEA,Minimum En-route Altitude
|
||||
OCTA,Outside Control Areas
|
||||
TA,Terminal Airspace
|
||||
TAS,Terminal Airspace System
|
||||
TMA,Terminal Control Area
|
||||
UTA,Upper Traffic Area
|
||||
VTC,Visual Terminal Chart
|
||||
|
46
Powershell/Data/Abbr/computer.csv
Normal file
46
Powershell/Data/Abbr/computer.csv
Normal file
@@ -0,0 +1,46 @@
|
||||
Abbreviation,Definition
|
||||
ACID,"Atomicity, Consistency, Isolation, Durability"
|
||||
ACL,Access Control List
|
||||
ADC,Analog-to-Digital Converter
|
||||
ADF,Automatic Document Feeder
|
||||
ADSL,Asymmetric Digital Subscriber Line
|
||||
AFP,Apple Filing Protocol
|
||||
AGP,Accelerated Graphics Port
|
||||
AIFF,Audio Interchange File Format
|
||||
ALU,Arithmetic Logic Unit
|
||||
ANSI,American National Standards Institute
|
||||
API,Application Programming Interface
|
||||
APU,Accelerated Processing Unit
|
||||
ARP,Address Resolution Protocol
|
||||
ASCII,American Standard Code for Information Interchange
|
||||
ASP,Application Service Provider
|
||||
ATM,Asynchronous Transfer Mode
|
||||
AVR,Audio/Video Receiver
|
||||
Bash,Bourne-Again Shell
|
||||
BASIC,Beginner's All-purpose Symbolic Instruction Code
|
||||
BCC,Blind Carbon Copy
|
||||
BIOS,Basic Input/Output System
|
||||
BLE,Bluetooth Low Energy
|
||||
Blob,Binary Large Object
|
||||
BMP,Bitmap
|
||||
BSOD,Blue Screen of Death
|
||||
CAD,Computer-Aided Design
|
||||
CAN,Campus Area Network
|
||||
CD,Compact Disc
|
||||
CPU,Central Processing Unit
|
||||
CSV,Comma Separated Values (file format)
|
||||
DDL,Data Definition Language
|
||||
IDE,Integrated Development Environment
|
||||
GPU,Graphics Processing Unit
|
||||
GUI,Graphical User Interface
|
||||
IP,Internet Protocol
|
||||
ISP,Internet Service Provider
|
||||
IT,Information Technology
|
||||
LAN,Local Area Network
|
||||
LCD,Liquid Crystal Display
|
||||
NIC,Network Interface Card
|
||||
PC,Personal Computer
|
||||
RAM,Random Access Memory
|
||||
URL,Uniform Resource Locator
|
||||
VPN,Virtual Private Network
|
||||
WAN,Wide Area Network
|
||||
|
42
Powershell/Data/Abbr/cooking.csv
Normal file
42
Powershell/Data/Abbr/cooking.csv
Normal file
@@ -0,0 +1,42 @@
|
||||
Abbreviation,Definition
|
||||
btl,Bottle
|
||||
c,Cup
|
||||
C,Cups
|
||||
DF,Dairy free
|
||||
doz,dozen
|
||||
dp,drop
|
||||
fl oz,Fluid ounce
|
||||
fl ozs,Fluid ounces
|
||||
g,Grams
|
||||
gal,Gallons
|
||||
gals,Gallons
|
||||
GF,Gluten free
|
||||
kg,Kilograms
|
||||
L,Litres
|
||||
l,Litres
|
||||
lb,Pound
|
||||
lbs,Pounds
|
||||
lg,large
|
||||
lge,large
|
||||
md,medium
|
||||
med,medium
|
||||
mg,Milligrams
|
||||
ml,Millilitres
|
||||
NRV,Nutrient Reference Value
|
||||
oz,Ounce
|
||||
ozs,Ounces
|
||||
pers,person(s)
|
||||
pn,Pinch
|
||||
pt,Pint
|
||||
pts,Pints
|
||||
qt,Quart
|
||||
qts,Quarts
|
||||
RI,Reference Intake
|
||||
serv,serving
|
||||
sm,small
|
||||
srv,serving
|
||||
Tbsp,Tablespoon
|
||||
tsp,Teaspoon
|
||||
VG,vegetarian
|
||||
VN,Vegan
|
||||
WF,Wheat free
|
||||
|
14
Powershell/Data/Abbr/medicine.csv
Normal file
14
Powershell/Data/Abbr/medicine.csv
Normal file
@@ -0,0 +1,14 @@
|
||||
Abbreviation,Definition
|
||||
PR,per the rectum
|
||||
pr,per the rectum
|
||||
PT,prothrombin time
|
||||
PTT,partial thromboplastin time
|
||||
pulv,powder
|
||||
PV,per the vagina
|
||||
q,every
|
||||
q12h,every 12 hours
|
||||
qd,daily
|
||||
q1d,daily
|
||||
q2h,every 2 hours
|
||||
q3h,every 3 hours
|
||||
q4h,every 4 hours
|
||||
|
81
Powershell/Data/Abbr/music.csv
Normal file
81
Powershell/Data/Abbr/music.csv
Normal file
@@ -0,0 +1,81 @@
|
||||
Abbreviation,Definition
|
||||
8va,Octave up
|
||||
ad lib,Ad Libitum (“freely”)
|
||||
afl,Alto flute
|
||||
AS,Al Segno (“To the sign”)
|
||||
bc,Basso Continuo (“continuous bass accompaniment”)
|
||||
bcl,Bass clarinet
|
||||
bfl,Bass flute
|
||||
bpm,Beats per minute
|
||||
bn,Bassoon
|
||||
bob,Bass oboe
|
||||
br,Brass instruments
|
||||
bstcl,Basset clarinet
|
||||
bsthn,Basset horn
|
||||
bug,Bugle
|
||||
cbcl,Contrabass clarinet
|
||||
cbn,Contrabassoon
|
||||
cf,Cantus Firmus (“main melody”)
|
||||
cl,Clarinet
|
||||
cresc,Crescendo (also noted as <)
|
||||
crt,Cornet
|
||||
D.C. al Coda,Da Capo al Coda (“from the beginning to the Coda sign”)
|
||||
D.C. al Fine,Da Capo al Fine (“from the beginning to the end”)
|
||||
D.S. al Fine,Dal Segno al Fine (“from the Segno mark to the end”)
|
||||
decresc,Descrescendo (also noted as >)
|
||||
dim,Diminuendo
|
||||
eh,English horn
|
||||
euph,Euphonium
|
||||
f,Forte
|
||||
fda,Flute d’amore (tenor flute)
|
||||
ff,Fortissimo
|
||||
fff,Fortississimo
|
||||
fgh,Flugelhorn
|
||||
fl,Flute
|
||||
fp,Fortepiano
|
||||
gliss,Glissando (“gliding, sliding”)
|
||||
hn,Horn
|
||||
m,Measure
|
||||
mm,Measures
|
||||
MM,Metronome tempo
|
||||
mf,Mezzo-Forte
|
||||
mp,Mezzo-Piano
|
||||
mvt,Movement
|
||||
ob,Oboe
|
||||
oda,Oboe d’amore
|
||||
orch,Orchestra
|
||||
p,Piano
|
||||
p,Page,
|
||||
pan,Pan flute
|
||||
pic,Piccolo
|
||||
picc,Piccolo
|
||||
pizz,Pizzicato (“plucking”)
|
||||
pp,Pianissio
|
||||
pp,Pages
|
||||
ppp,Pianississimo
|
||||
rall,Rallentando (“gradual slowing”)
|
||||
rec,Recorder
|
||||
rit,Ritardando (“slowing down”)
|
||||
Rf,Rinforzando (“with sudden force”)
|
||||
Rfz,Rinforzando (“with sudden force”)
|
||||
rpm,Revolutions per minute
|
||||
sax,Saxophone
|
||||
sf,Sforzando, Sforzato (“sudden accent”)
|
||||
sfz,Sforzando, Sforzato (“sudden accent”)
|
||||
sfp,Sforzando followed by Piano
|
||||
smorz,Smorzando (“dying away”)
|
||||
sord,Sordino (“muted”)
|
||||
sost. ped,Sostenuto pedal (“sustained pedal”)
|
||||
spicc,Spiccato (“bounce bow on a stringed instrument”)
|
||||
stacc,Staccato (“playing each note separately from the others”)
|
||||
stpt,Slide trumpet
|
||||
sul pont,Sul Ponticello (“playing with the bow near the bridge”)
|
||||
tba,Tuba
|
||||
tbn,Trombone
|
||||
tpt,Trumpet
|
||||
tr,Trill
|
||||
trem,Tremolo (“trembling, wavering”)
|
||||
tsx,Tenor saxophone
|
||||
vib,Vibrato (“pulsing, vibrating”)
|
||||
vol,Volume
|
||||
ww,Woodwinds
|
||||
|
5843
Powershell/Data/Abbr/various.csv
Normal file
5843
Powershell/Data/Abbr/various.csv
Normal file
File diff suppressed because it is too large
Load Diff
6
Powershell/Data/Checklists/handwashing.txt
Normal file
6
Powershell/Data/Checklists/handwashing.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
HEAD Handwashing
|
||||
Wet your hands with clean, running water (warm or cold), turn off the tap, and apply soap.
|
||||
Lather your hands by rubbing them together with the soap. Lather the backs of your hands, between your fingers, and under your nails.
|
||||
Scrub your hands for at least 20 seconds.
|
||||
Rinse your hands well under clean, running water.
|
||||
Dry your hands using a clean towel or air dry them.
|
||||
45
Powershell/Data/Help/WindowsTerminal.txt
Normal file
45
Powershell/Data/Help/WindowsTerminal.txt
Normal file
@@ -0,0 +1,45 @@
|
||||
Windows Terminal Cheat Sheet
|
||||
============================
|
||||
|
||||
Application
|
||||
-----------
|
||||
Alt-F4 Close window
|
||||
Ctrl-Shift-f Find
|
||||
Ctrl-Shift-Space Open dropdown
|
||||
Ctrl-, Open settings file
|
||||
Alt-Enter Toggle full screen
|
||||
F11
|
||||
|
||||
Tab Commands
|
||||
------------
|
||||
Ctrl-Shift-d Duplicate tab
|
||||
Ctrl-Shift-t New tab
|
||||
Ctrl-Shift-p New tab from profile p=1..9
|
||||
Ctrl-Tab Switch to next tab
|
||||
Ctrl-Shift-Tab Switch to previous tab
|
||||
Ctrl-Alt-n Switch to tab n=0..9
|
||||
|
||||
Pane Commands
|
||||
-------------
|
||||
Alt-Shift-d Split pane optimally. Active profile.
|
||||
Alt-Shift-- Split pane horizontally. Default profile.
|
||||
Alt-Shift-+ Split pane vertically. Default profile.
|
||||
Ctrl-Shift-w Close innermost pane, tab, or window
|
||||
|
||||
Clipboard Commands
|
||||
------------------
|
||||
Ctrl-c Copy
|
||||
Ctrl-v Paste
|
||||
|
||||
Scrollback Commands
|
||||
-------------------
|
||||
Ctrl-Shift-up Scroll up
|
||||
Ctrl-Shift-down Scroll down
|
||||
Ctrl-Shift-pgup Scroll page up
|
||||
Ctrl-Shift-pgdn Scroll page down
|
||||
|
||||
Visual Adjustment Commands
|
||||
--------------------------
|
||||
Ctrl-= Increase font size
|
||||
Ctrl-- Decrease font size
|
||||
Ctrl-0 Reset font size
|
||||
29191
Powershell/Data/IEEE-MAC-vendors.csv
Normal file
29191
Powershell/Data/IEEE-MAC-vendors.csv
Normal file
File diff suppressed because it is too large
Load Diff
185
Powershell/Data/ISO639-1-language-codes.csv
Normal file
185
Powershell/Data/ISO639-1-language-codes.csv
Normal file
@@ -0,0 +1,185 @@
|
||||
alpha2,English
|
||||
aa,Afar
|
||||
ab,Abkhazian
|
||||
ae,Avestan
|
||||
af,Afrikaans
|
||||
ak,Akan
|
||||
am,Amharic
|
||||
an,Aragonese
|
||||
ar,Arabic
|
||||
as,Assamese
|
||||
av,Avaric
|
||||
ay,Aymara
|
||||
az,Azerbaijani
|
||||
ba,Bashkir
|
||||
be,Belarusian
|
||||
bg,Bulgarian
|
||||
bh,Bihari languages
|
||||
bi,Bislama
|
||||
bm,Bambara
|
||||
bn,Bengali
|
||||
bo,Tibetan
|
||||
br,Breton
|
||||
bs,Bosnian
|
||||
ca,Catalan; Valencian
|
||||
ce,Chechen
|
||||
ch,Chamorro
|
||||
co,Corsican
|
||||
cr,Cree
|
||||
cs,Czech
|
||||
cu,Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic
|
||||
cv,Chuvash
|
||||
cy,Welsh
|
||||
da,Danish
|
||||
de,German
|
||||
dv,Divehi; Dhivehi; Maldivian
|
||||
dz,Dzongkha
|
||||
ee,Ewe
|
||||
el,"Greek, Modern (1453-)"
|
||||
en,English
|
||||
eo,Esperanto
|
||||
es,Spanish; Castilian
|
||||
et,Estonian
|
||||
eu,Basque
|
||||
fa,Persian
|
||||
ff,Fulah
|
||||
fi,Finnish
|
||||
fj,Fijian
|
||||
fo,Faroese
|
||||
fr,French
|
||||
fy,Western Frisian
|
||||
ga,Irish
|
||||
gd,Gaelic; Scottish Gaelic
|
||||
gl,Galician
|
||||
gn,Guarani
|
||||
gu,Gujarati
|
||||
gv,Manx
|
||||
ha,Hausa
|
||||
he,Hebrew
|
||||
hi,Hindi
|
||||
ho,Hiri Motu
|
||||
hr,Croatian
|
||||
ht,Haitian; Haitian Creole
|
||||
hu,Hungarian
|
||||
hy,Armenian
|
||||
hz,Herero
|
||||
ia,Interlingua (International Auxiliary Language Association)
|
||||
id,Indonesian
|
||||
ie,Interlingue; Occidental
|
||||
ig,Igbo
|
||||
ii,Sichuan Yi; Nuosu
|
||||
ik,Inupiaq
|
||||
io,Ido
|
||||
is,Icelandic
|
||||
it,Italian
|
||||
iu,Inuktitut
|
||||
ja,Japanese
|
||||
jv,Javanese
|
||||
ka,Georgian
|
||||
kg,Kongo
|
||||
ki,Kikuyu; Gikuyu
|
||||
kj,Kuanyama; Kwanyama
|
||||
kk,Kazakh
|
||||
kl,Kalaallisut; Greenlandic
|
||||
km,Central Khmer
|
||||
kn,Kannada
|
||||
ko,Korean
|
||||
kr,Kanuri
|
||||
ks,Kashmiri
|
||||
ku,Kurdish
|
||||
kv,Komi
|
||||
kw,Cornish
|
||||
ky,Kirghiz; Kyrgyz
|
||||
la,Latin
|
||||
lb,Luxembourgish; Letzeburgesch
|
||||
lg,Ganda
|
||||
li,Limburgan; Limburger; Limburgish
|
||||
ln,Lingala
|
||||
lo,Lao
|
||||
lt,Lithuanian
|
||||
lu,Luba-Katanga
|
||||
lv,Latvian
|
||||
mg,Malagasy
|
||||
mh,Marshallese
|
||||
mi,Maori
|
||||
mk,Macedonian
|
||||
ml,Malayalam
|
||||
mn,Mongolian
|
||||
mr,Marathi
|
||||
ms,Malay
|
||||
mt,Maltese
|
||||
my,Burmese
|
||||
na,Nauru
|
||||
nb,"Bokmål, Norwegian; Norwegian Bokmål"
|
||||
nd,"Ndebele, North; North Ndebele"
|
||||
ne,Nepali
|
||||
ng,Ndonga
|
||||
nl,Dutch; Flemish
|
||||
nn,"Norwegian Nynorsk; Nynorsk, Norwegian"
|
||||
no,Norwegian
|
||||
nr,"Ndebele, South; South Ndebele"
|
||||
nv,Navajo; Navaho
|
||||
ny,Chichewa; Chewa; Nyanja
|
||||
oc,Occitan (post 1500)
|
||||
oj,Ojibwa
|
||||
om,Oromo
|
||||
or,Oriya
|
||||
os,Ossetian; Ossetic
|
||||
pa,Panjabi; Punjabi
|
||||
pi,Pali
|
||||
pl,Polish
|
||||
ps,Pushto; Pashto
|
||||
pt,Portuguese
|
||||
qu,Quechua
|
||||
rm,Romansh
|
||||
rn,Rundi
|
||||
ro,Romanian; Moldavian; Moldovan
|
||||
ru,Russian
|
||||
rw,Kinyarwanda
|
||||
sa,Sanskrit
|
||||
sc,Sardinian
|
||||
sd,Sindhi
|
||||
se,Northern Sami
|
||||
sg,Sango
|
||||
si,Sinhala; Sinhalese
|
||||
sk,Slovak
|
||||
sl,Slovenian
|
||||
sm,Samoan
|
||||
sn,Shona
|
||||
so,Somali
|
||||
sq,Albanian
|
||||
sr,Serbian
|
||||
ss,Swati
|
||||
st,"Sotho, Southern"
|
||||
su,Sundanese
|
||||
sv,Swedish
|
||||
sw,Swahili
|
||||
ta,Tamil
|
||||
te,Telugu
|
||||
tg,Tajik
|
||||
th,Thai
|
||||
ti,Tigrinya
|
||||
tk,Turkmen
|
||||
tl,Tagalog
|
||||
tn,Tswana
|
||||
to,Tonga (Tonga Islands)
|
||||
tr,Turkish
|
||||
ts,Tsonga
|
||||
tt,Tatar
|
||||
tw,Twi
|
||||
ty,Tahitian
|
||||
ug,Uighur; Uyghur
|
||||
uk,Ukrainian
|
||||
ur,Urdu
|
||||
uz,Uzbek
|
||||
ve,Venda
|
||||
vi,Vietnamese
|
||||
vo,Volapük
|
||||
wa,Walloon
|
||||
wo,Wolof
|
||||
xh,Xhosa
|
||||
yi,Yiddish
|
||||
yo,Yoruba
|
||||
za,Zhuang; Chuang
|
||||
zh,Chinese
|
||||
zu,Zulu
|
||||
|
21
Powershell/Data/TIOBE-index.csv
Normal file
21
Powershell/Data/TIOBE-index.csv
Normal file
@@ -0,0 +1,21 @@
|
||||
Language, Popularity, Change
|
||||
C, 12.54, -4.65
|
||||
Python, 11.84, +3.48
|
||||
Java, 11.54, -4.56
|
||||
C++, 7.36, +1.41
|
||||
C#, 4.33, -0.40
|
||||
Visual Basic, 4.01, -0.68
|
||||
JavaScript, 2.33, +0.06
|
||||
PHP, 2.21, -0.05
|
||||
Assembly language, 2.05, +1.09
|
||||
SQL, 1.88, +0.15
|
||||
Classic Visual Basic, 1.72, +1.07
|
||||
Groovy, 1.29, +0.87
|
||||
Ruby, 1.23, +0.25
|
||||
R, 1.20, -0.99
|
||||
Perl, 1.18, +0.36
|
||||
Swift, 1.10, -0.35
|
||||
Fortran, 1.07, +0.80
|
||||
Delphi/Object Pascal, 1.06, +0.47
|
||||
MATLAB, 1.05, +0.15
|
||||
Go, 0.95, -0.06
|
||||
|
178
Powershell/Data/domain-names.csv
Normal file
178
Powershell/Data/domain-names.csv
Normal file
@@ -0,0 +1,178 @@
|
||||
Domain
|
||||
3sat.de
|
||||
access.ing.de
|
||||
accounts.google.com
|
||||
activity.windows.com
|
||||
airbnb.com
|
||||
airbnb.de
|
||||
aka.ms
|
||||
aldi-nord.de
|
||||
aldi-sued.de
|
||||
all-in.de
|
||||
allgaeuer-zeitung.de
|
||||
alternate.de
|
||||
api.dropboxapi.com
|
||||
api.met.no
|
||||
api1.origin.com
|
||||
arc.msn.com
|
||||
arte.tv
|
||||
assets.msn.com
|
||||
amazon.com
|
||||
amazon.de
|
||||
amazon.fr
|
||||
atcsim.de
|
||||
banking.ing-diba.de
|
||||
bergwelten.com
|
||||
bild.de
|
||||
bing.com
|
||||
bing.de
|
||||
bing.fr
|
||||
blitzortung.org
|
||||
bolt.dropbox.com
|
||||
br.de
|
||||
catalog.gamepass.com
|
||||
changelogs.ubuntu.com
|
||||
chip.de
|
||||
client.dropbox.com
|
||||
client.wns.windows.com
|
||||
clients1.google.com
|
||||
clients2.google.com
|
||||
clients3.google.com
|
||||
clients4.google.com
|
||||
contacts.google.com
|
||||
d.dropbox.com
|
||||
dasoertliche.de
|
||||
dealer.spotify.com
|
||||
deepl.com
|
||||
dell.com
|
||||
discord.com
|
||||
discordapp.com
|
||||
dhl.de
|
||||
download.windowsupdate.com
|
||||
dropbox.com
|
||||
earth.google.com
|
||||
ebay.com
|
||||
ebay.de
|
||||
ebay.fr
|
||||
ebay-kleinanzeigen.de
|
||||
ebook3000.com
|
||||
facebook.com
|
||||
facebook.de
|
||||
facebook.fr
|
||||
fleschutz.de
|
||||
flightradar24.com
|
||||
focus.de
|
||||
fonts.google.com
|
||||
fonts.googleapis.com
|
||||
fonts.gstatic.com
|
||||
fosbos-kempten.de
|
||||
github.com
|
||||
github.map.fastly.net
|
||||
gmail.com
|
||||
golem.de
|
||||
google.com
|
||||
google.de
|
||||
google.fr
|
||||
googleapis.com
|
||||
gstatic.com
|
||||
heise.de
|
||||
holidaycheck.de
|
||||
hornbach.de
|
||||
i.ytimg.com
|
||||
IEEE.org
|
||||
ibm.com
|
||||
icons8.com
|
||||
imap.googlemail.com
|
||||
ing.de
|
||||
install.robertsspaceindustries.com
|
||||
ipfs.io
|
||||
ipv6.msftconnecttest.com
|
||||
launcher2.robertsspaceindustries.com
|
||||
licensing.mp.microsoft.com
|
||||
lidl.de
|
||||
live.github.com
|
||||
live.thunderbird.net
|
||||
livepatch.canonical.com
|
||||
login.live.com
|
||||
login.hrworks.de
|
||||
longfiles.com
|
||||
mail.google.com
|
||||
map.blitzortung.org
|
||||
maps.google.com
|
||||
maps.google.de
|
||||
maps.google.fr
|
||||
mebis.bayern.de
|
||||
microsoft.com
|
||||
mozilla.org
|
||||
mtalk.google.com
|
||||
music.google.com
|
||||
mwittrien.github.io
|
||||
netbeat.de
|
||||
netflix.com
|
||||
news.google.com
|
||||
news.google.de
|
||||
news.google.fr
|
||||
news.url.google.com
|
||||
notube.net
|
||||
ogs.google.com
|
||||
opera.com
|
||||
photos.google.com
|
||||
pixabay.com
|
||||
play.google.com
|
||||
plex.tv
|
||||
posaunenchor-guenzach.de
|
||||
presence.teams.microsoft.com
|
||||
ptbtime1.ptb.de
|
||||
ptbtime2.ptb.de
|
||||
ptbtime3.ptb.de
|
||||
rb-allgaeuerland.de
|
||||
realschule-oberguenzburg.de
|
||||
redbull.tv
|
||||
redhat.com
|
||||
reichelt.de
|
||||
robertsspaceindustries.com
|
||||
schneier.com
|
||||
secure.download.dm.origin.com
|
||||
semonkeys.net
|
||||
settings.data.microsoft.com
|
||||
settings-win.data.microsoft.com
|
||||
sites.google.com
|
||||
slashdot.com
|
||||
speedtest.net
|
||||
ssl.gstatic.com
|
||||
stackoverflow.com
|
||||
start.thunderbird.net
|
||||
static.focus.de
|
||||
static.nvidiagrid.net
|
||||
storage.googleapis.com
|
||||
substrate.office.com
|
||||
t-online.de
|
||||
t0.gstatic.com
|
||||
tchibo.de
|
||||
teams.microsoft.com
|
||||
techstage.de
|
||||
telemetry.dropbox.com
|
||||
tile-service.weather.microsoft.com
|
||||
time.windows.com
|
||||
toggl.com
|
||||
toom.de
|
||||
track.toggl.com
|
||||
translate.google.de
|
||||
twitter.com
|
||||
twitter.de
|
||||
ubuntu.com
|
||||
ufainc.com
|
||||
update.googleapis.com
|
||||
wetter.com
|
||||
wetter.de
|
||||
wired.com
|
||||
ws-kempten.de
|
||||
wttr.in
|
||||
www.google.com
|
||||
www.googleapis.com
|
||||
www.gstatic.com
|
||||
www.netflix.com
|
||||
www.youtube.com
|
||||
youtube.com
|
||||
youtube.de
|
||||
zdf.de
|
||||
|
2766
Powershell/Data/exit-codes.csv
Normal file
2766
Powershell/Data/exit-codes.csv
Normal file
File diff suppressed because it is too large
Load Diff
25
Powershell/Data/git-repos.csv
Normal file
25
Powershell/Data/git-repos.csv
Normal file
@@ -0,0 +1,25 @@
|
||||
Category,FolderName,Branch,Shallow,URL
|
||||
Dev, base256unicode,master, no, "https://github.com/fleschutz/base256unicode"
|
||||
Dev, bazel, master, yes, "https://github.com/bazelbuild/bazel"
|
||||
Dev, cmake, master, yes, "https://github.com/Kitware/CMake"
|
||||
Fun, cmatrix, master, yes, "https://github.com/abishekvashok/cmatrix"
|
||||
Tool, cmark, master, yes, "https://github.com/commonmark/cmark"
|
||||
Dev, CWTS, master, no, "https://github.com/fleschutz/CWTS"
|
||||
Tool, elasticsearch, master, yes, "https://github.com/elastic/elasticsearch"
|
||||
Tool, go-ipfs, master, yes, "https://github.com/ipfs/go-ipfs"
|
||||
Tool, grafana, main, yes, "https://github.com/grafana/grafana"
|
||||
Dev, llvm, master, yes, "https://github.com/llvm/llvm-project"
|
||||
Math, LSS, master, yes, "https://github.com/fleschutz/LSS"
|
||||
Dev, ninja, master, yes, "git://github.com/ninja-build/ninja.git"
|
||||
Libs, opencv, master, yes, "https://github.com/opencv/opencv"
|
||||
Tool, OSMA, master, no, "https://github.com/fleschutz/OSMA"
|
||||
Shell, PowerShell, master, no, "https://github.com/fleschutz/PowerShell"
|
||||
Shell, pwsh, master, yes, "https://github.com/PowerShell/PowerShell"
|
||||
Dev, protobuf, master, yes, "https://github.com/protocolbuffers/protobuf"
|
||||
Dev, rust, master, yes, "https://github.com/rust-lang/rust"
|
||||
Tool, smartmontools, master, yes, "https://github.com/smartmontools/smartmontools"
|
||||
Tool, tensorflow, master, yes, "https://github.com/tensorflow/tensorflow"
|
||||
Tool, terminal, main, yes, "https://github.com/microsoft/terminal"
|
||||
Dev, tinycc, mob, yes, "https://github.com/TinyCC/tinycc"
|
||||
Tool, voice2json, master, yes, "https://github.com/synesthesiam/voice2json"
|
||||
Tool, zfs, master, yes, "https://github.com/openzfs/zfs"
|
||||
|
65
Powershell/Data/http-status-codes.csv
Normal file
65
Powershell/Data/http-status-codes.csv
Normal file
@@ -0,0 +1,65 @@
|
||||
"StatusCode","Type","ShortDescription","LongDescription"
|
||||
"100","Informational","Continue ","The initial part of a request has been received and has not yet been rejected by the server. The server intends to send a final response after the request has been fully received and acted upon."
|
||||
"101","Informational","Switching Protocols ","The server understands and is willing to comply with the client's request, via the Upgrade header field1, for a change in the application protocol being used on this connection."
|
||||
"102","Informational","Processing ","An interim response used to inform the client that the server has accepted the complete request, but has not yet completed it."
|
||||
"200","Success","OK ","The request has succeeded."
|
||||
"201","Success","Created ","The request has been fulfilled and has resulted in one or more new resources being created."
|
||||
"202","Success","Accepted ","The request has been accepted for processing, but the processing has not been completed. The request might or might not eventually be acted upon, as it might be disallowed when processing actually takes place."
|
||||
"203","Success","Non-authoritative Information ","The request was successful but the enclosed payload has been modified from that of the origin server's 200 OK response by a transforming proxy1."
|
||||
"204","Success","No Content ","The server has successfully fulfilled the request and that there is no additional content to send in the response payload body."
|
||||
"205","Success","Reset Content ","The server has fulfilled the request and desires that the user agent reset the ""document view"", which caused the request to be sent, to its original state as received from the origin server."
|
||||
"206","Success","Partial Content ","The server is successfully fulfilling a range request for the target resource by transferring one or more parts of the selected representation that correspond to the satisfiable ranges found in the request's Range header field1."
|
||||
"207","Success","Multi-Status ","A Multi-Status response conveys information about multiple resources in situations where multiple status codes might be appropriate."
|
||||
"208","Success","Already Reported ","Used inside a DAV: propstat response element to avoid enumerating the internal members of multiple bindings to the same collection repeatedly."
|
||||
"226","Success","IM Used ","The server has fulfilled a GET request for the resource, and the response is a representation of the result of one or more instance-manipulations applied to the current instance."
|
||||
"300","Redirection","Multiple Choices ","The target resource has more than one representation, each with its own more specific identifier, and information about the alternatives is being provided so that the user (or user agent) can select a preferred representation by redirecting its request to one or more of those identifiers."
|
||||
"301","Redirection","Moved Permanently ","The target resource has been assigned a new permanent URI and any future references to this resource ought to use one of the enclosed URIs."
|
||||
"302","Redirection","Found ","The target resource resides temporarily under a different URI. Since the redirection might be altered on occasion, the client ought to continue to use the effective request URI for future requests."
|
||||
"303","Redirection","See Other ","The server is redirecting the user agent to a different resource, as indicated by a URI in the Location header field, which is intended to provide an indirect response to the original request."
|
||||
"304","Redirection","Not Modified ","A conditional GET or HEAD request has been received and would have resulted in a 200 OK response if it were not for the fact that the condition evaluated to false."
|
||||
"305","Redirection","Use Proxy ","Defined in a previous version of this specification and is now deprecated, due to security concerns regarding in-band configuration of a proxy."
|
||||
"307","Redirection","Temporary Redirect ","The target resource resides temporarily under a different URI and the user agent MUST NOT change the request method if it performs an automatic redirection to that URI."
|
||||
"308","Redirection","Permanent Redirect ","The target resource has been assigned a new permanent URI and any future references to this resource ought to use one of the enclosed URIs."
|
||||
"400","Client Error","Bad Request ","The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing)."
|
||||
"401","Client Error","Unauthorized ","The request has not been applied because it lacks valid authentication credentials for the target resource."
|
||||
"402","Client Error","Payment Required ","Reserved for future use."
|
||||
"403","Client Error","Forbidden ","The server understood the request but refuses to authorize it."
|
||||
"404","Client Error","Not Found ","The origin server did not find a current representation for the target resource or is not willing to disclose that one exists."
|
||||
"405","Client Error","Method Not Allowed ","The method received in the request-line is known by the origin server but not supported by the target resource."
|
||||
"406","Client Error","Not Acceptable ","The target resource does not have a current representation that would be acceptable to the user agent, according to the proactive negotiation header fields received in the request1, and the server is unwilling to supply a default representation."
|
||||
"407","Client Error","Proxy Authentication Required ","Similar to 401 Unauthorized, but it indicates that the client needs to authenticate itself in order to use a proxy."
|
||||
"408","Client Error","Request Timeout ","The server did not receive a complete request message within the time that it was prepared to wait."
|
||||
"409","Client Error","Conflict ","The request could not be completed due to a conflict with the current state of the target resource. This code is used in situations where the user might be able to resolve the conflict and resubmit the request."
|
||||
"410","Client Error","Gone ","The target resource is no longer available at the origin server and that this condition is likely to be permanent."
|
||||
"411","Client Error","Length Required ","The server refuses to accept the request without a defined Content-Length1."
|
||||
"412","Client Error","Precondition Failed ","One or more conditions given in the request header fields evaluated to false when tested on the server."
|
||||
"413","Client Error","Payload Too Large ","The server is refusing to process a request because the request payload is larger than the server is willing or able to process."
|
||||
"414","Client Error","Request-URI Too Long ","The server is refusing to service the request because the request-target1 is longer than the server is willing to interpret."
|
||||
"415","Client Error","Unsupported Media Type ","The origin server is refusing to service the request because the payload is in a format not supported by this method on the target resource."
|
||||
"416","Client Error","Requested Range Not Satisfiable ","None of the ranges in the request's Range header field1 overlap the current extent of the selected resource or that the set of ranges requested has been rejected due to invalid ranges or an excessive request of small or overlapping ranges."
|
||||
"417","Client Error","Expectation Failed ","The expectation given in the request's Expect header field1 could not be met by at least one of the inbound servers."
|
||||
"418","Client Error","I'm a teapot ","Any attempt to brew coffee with a teapot should result in the error code ""418 I'm a teapot"". The resulting entity body MAY be short and stout."
|
||||
"421","Client Error","Misdirected Request ","The request was directed at a server that is not able to produce a response. This can be sent by a server that is not configured to produce responses for the combination of scheme and authority that are included in the request URI."
|
||||
"422","Client Error","Unprocessable Entity ","The server understands the content type of the request entity (hence a 415 Unsupported Media Type status code is inappropriate), and the syntax of the request entity is correct (thus a 400 Bad Request status code is inappropriate) but was unable to process the contained instructions."
|
||||
"423","Client Error","Locked ","The source or destination resource of a method is locked."
|
||||
"424","Client Error","Failed Dependency ","The method could not be performed on the resource because the requested action depended on another action and that action failed."
|
||||
"426","Client Error","Upgrade Required ","The server refuses to perform the request using the current protocol but might be willing to do so after the client upgrades to a different protocol."
|
||||
"428","Client Error","Precondition Required ","The origin server requires the request to be conditional."
|
||||
"429","Client Error","Too Many Requests ","The user has sent too many requests in a given amount of time (""rate limiting"")."
|
||||
"431","Client Error","Request Header Fields Too Large ","The server is unwilling to process the request because its header fields are too large. The request MAY be resubmitted after reducing the size of the request header fields."
|
||||
"444","Client Error","Connection Closed Without Response ","A non-standard status code used to instruct nginx to close the connection without sending a response to the client, most commonly used to deny malicious or malformed requests."
|
||||
"451","Client Error","Unavailable For Legal Reasons ","The server is denying access to the resource as a consequence of a legal demand."
|
||||
"499","Client Error","Client Closed Request ","A non-standard status code introduced by nginx for the case when a client closes the connection while nginx is processing the request."
|
||||
"500","Server Error","Internal Server Error ","The server encountered an unexpected condition that prevented it from fulfilling the request."
|
||||
"501","Server Error","Not Implemented ","The server does not support the functionality required to fulfill the request."
|
||||
"502","Server Error","Bad Gateway ","The server, while acting as a gateway or proxy, received an invalid response from an inbound server it accessed while attempting to fulfill the request."
|
||||
"503","Server Error","Service Unavailable ","The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay."
|
||||
"504","Server Error","Gateway Timeout ","The server, while acting as a gateway or proxy, did not receive a timely response from an upstream server it needed to access in order to complete the request."
|
||||
"505","Server Error","HTTP Version Not Supported ","The server does not support, or refuses to support, the major version of HTTP that was used in the request message."
|
||||
"506","Server Error","Variant Also Negotiates ","The server has an internal configuration error: the chosen variant resource is configured to engage in transparent content negotiation itself, and is therefore not a proper end point in the negotiation process."
|
||||
"507","Server Error","Insufficient Storage ","The method could not be performed on the resource because the server is unable to store the representation needed to successfully complete the request."
|
||||
"508","Server Error","Loop Detected ","The server terminated an operation because it encountered an infinite loop while processing a request with ""Depth: infinity"". This status indicates that the entire operation failed."
|
||||
"510","Server Error","Not Extended ","The policy for accessing the resource has not been met in the request. The server should send back all the information necessary for the client to issue an extended request."
|
||||
"511","Server Error","Network Authentication Required ","The client needs to authenticate to gain network access."
|
||||
"599","Server Error","Network Connect Timeout Error ","This status code is not specified in any RFCs, but is used by some HTTP proxies to signal a network connect timeout behind the proxy to a client in front of the proxy."
|
||||
|
||||
|
69
Powershell/Data/jokes.csv
Normal file
69
Powershell/Data/jokes.csv
Normal file
@@ -0,0 +1,69 @@
|
||||
Joke
|
||||
"Chuck Norris doesnt read books. He stares them down until he gets the information he wants."
|
||||
"Time waits for no man. Unless that man is Chuck Norris."
|
||||
"If you spell Chuck Norris in Scrabble, you win. Forever."
|
||||
"Chuck Norris breathes air five times a day."
|
||||
"In the Beginning there was nothing then Chuck Norris roundhouse kicked nothing and told it to get a job."
|
||||
"Chuck Norris has a mug of nails instead of coffee in the morning."
|
||||
"If Chuck Norris were to travel to an alternate dimension in which there was another Chuck Norris and they both fought, they would both win."
|
||||
"The dinosaurs looked at Chuck Norris the wrong way once. You know what happened to them."
|
||||
"Chuck Norris tears cure cancer. Too bad he has never cried."
|
||||
"Chuck Norris once roundhouse kicked someone so hard that his foot broke the speed of light"
|
||||
"Since 1940, the year Chuck Norris was born, roundhouse kick related deaths have increased 13,000 percent."
|
||||
"Chuck Norris does not own a stove, oven, or microwave , because revenge is a dish best served cold."
|
||||
"Chuck Norris does not sleep. He waits."
|
||||
"There is no chin behind Chuck Norris beard. There is only another fist."
|
||||
"The chief export of Chuck Norris is pain."
|
||||
"Chuck Norris recently had the idea to sell his pee as a canned beverage. Its now called Red Bull."
|
||||
"If paper beats rock, rock beats scissors, and scissors beats paper, what beats all 3 at the same time? Chuck Norris."
|
||||
"On the 7th day, God rested Chuck Norris took over."
|
||||
"Chuck Norris can dribble a bowling ball."
|
||||
"Chuck Norris drinks napalm to fight his heartburn."
|
||||
"Chuck Norris roundhouse kick is so powerful, it can be seen from outer space by the naked eye."
|
||||
"If you want a list of Chuck Norris enemies, just check the extinct species list."
|
||||
"Chuck Norris has never blinked in his entire life. Never."
|
||||
"Chuck Norris does not use spell check. If he happens to misspell a word, Oxford will change the spelling."
|
||||
"Some kids pee their name in the snow. Chuck Norris can pee his name into concrete."
|
||||
"Chuck Norris counted to infinity twice."
|
||||
"Chuck Norris can speak Braille."
|
||||
"Chuck Norris can have both feet on the ground and kick butt at the same time."
|
||||
"Chuck Norris can do a wheelie on a unicycle."
|
||||
"Chuck Norris stands faster than anyone can run."
|
||||
"Once a cobra bit Chuck Norris leg. After five days of excruciating pain, the cobra died."
|
||||
"Chuck Norris once won a game of Connect Four in three moves."
|
||||
"Champions are the breakfast of Chuck Norris."
|
||||
"When the Boogeyman goes to sleep every night he checks his closet for Chuck Norris."
|
||||
"Chuck Norris can slam revolving doors."
|
||||
"Chuck Norris does not hunt because the word hunting implies the possibility of failure. Chuck Norris goes killing."
|
||||
"The dark is afraid of Chuck Norris."
|
||||
"Chuck Norris makes onions cry."
|
||||
"Death once had a near-Chuck-Norris experience."
|
||||
"When Chuck Norris writes, he makes paper bleed."
|
||||
"Chuck Norris can strangle you with a cordless phone."
|
||||
"Chuck Norris never retreats; He just attacks in the opposite direction."
|
||||
"Chuck Norris can build a snowman out of rain."
|
||||
"Chuck Norris can drown a fish."
|
||||
"When Chuck Norris enters a room, he doesnt turn the lights on, he turns the dark off."
|
||||
"The only time Chuck Norris was ever wrong was when he thought he had made a mistake."
|
||||
"Chuck Norris is the only person that can punch a cyclops between the eye."
|
||||
"Chuck Norris used to beat up his shadow because it was following to close. It now stands 15 feet behind him."
|
||||
"Outer space exists because its afraid to be on the same planet with Chuck Norris."
|
||||
"When Chuck Norris does a pushup, he's pushing the Earth down."
|
||||
"Chuck Norris doesnt wear a watch. He decides what time it is."
|
||||
"Chuck Norris does not get frostbite. Chuck Norris bites frost."
|
||||
"Chuck Norris spices up his steaks with pepper spray."
|
||||
"The Great Wall of China was originally created to keep Chuck Norris out. It didn't work."
|
||||
"Chuck Norris can get in a bucket and lift it up with himself in it."
|
||||
"Chuck Norris doesn't shower, he only takes blood baths."
|
||||
"Chuck Norris can divide by zero."
|
||||
"Chuck Norris once kicked a horse in the chin. Its descendants are now known as giraffes."
|
||||
"When Chuck Norris does division, there are no remainders."
|
||||
"It takes Chuck Norris 20 minutes to watch '60 Minutes'."
|
||||
"Chuck Norris once went skydiving, but promised never to do it again. One Grand Canyon is enough."
|
||||
"We live in an expanding universe. All of it is trying to get away from Chuck Norris."
|
||||
"Chuck Norris beat the sun in a staring contest."
|
||||
"Chuck Norris can clap with one hand."
|
||||
"Chuck Norris doesn't need to shave. His beard is scared to grow."
|
||||
"Chuck Norris invented airplanes because he was tired of being the only person that could fly."
|
||||
"Freddy Krueger has nightmares about Chuck Norris."
|
||||
"Chuck Norris can start a fire with an ice cube."
|
||||
|
29
Powershell/Data/matrix.csv
Normal file
29
Powershell/Data/matrix.csv
Normal file
@@ -0,0 +1,29 @@
|
||||
A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
|
||||
" ","P"," "," "," "," ","H"," "," "," ","R"," "," "," "," "," "," "," ","B"," "," "," "," "," ","M"
|
||||
" ","O"," "," "," "," ","A"," "," "," ","E"," "," "," "," "," "," "," ","L"," "," "," "," "," ","A"
|
||||
" ","W"," "," "," "," ","V"," "," "," ","D"," "," "," "," "," "," "," ","U"," "," "," "," "," ","T"
|
||||
" ","E"," "," "," "," ","E"," "," "," "," "," "," "," "," "," "," "," ","E"," "," "," "," "," ","R"
|
||||
" ","R"," "," "," "," "," "," "," "," ","P"," "," "," "," "," "," "," "," "," "," "," "," "," ","I"
|
||||
" ","S"," "," "," "," ","F"," "," "," ","I"," "," "," "," "," "," "," ","P"," "," "," "," "," ","X"
|
||||
" ","H"," "," "," "," ","U"," "," "," ","L"," "," "," "," "," "," "," ","I"," "," "," "," "," "," "
|
||||
" ","E"," "," "," "," ","N"," "," "," ","L"," "," "," "," "," "," "," ","L"," "," "," "," "," "," "
|
||||
" ","L"," "," "," "," "," "," "," "," ","?"," "," "," "," "," "," "," ","L"," "," "," "," "," "," "
|
||||
" ","L"," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," ","?"," "," "," "," "," "," "
|
||||
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" ","R"," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" ","U"," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" ","L"," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" ","E"," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" ","S"," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "
|
||||
|
13297
Powershell/Data/ports.csv
Normal file
13297
Powershell/Data/ports.csv
Normal file
File diff suppressed because it is too large
Load Diff
217
Powershell/Data/scripts.csv
Normal file
217
Powershell/Data/scripts.csv
Normal file
@@ -0,0 +1,217 @@
|
||||
Script,Description
|
||||
add-firewall-rules.ps1, adds firewall rules to the given executables (needs admin rights)
|
||||
add-memo.ps1, adds the given memo text to $HOME/Memos.csv
|
||||
cd-desktop.ps1, go to the user's desktop folder
|
||||
cd-docs.ps1, go to the user's documents folder
|
||||
cd-downloads.ps1, go to the user's downloads folder
|
||||
cd-dropbox.ps1, go to the user's Dropbox folder
|
||||
cd-home.ps1, go to the user's home folder
|
||||
cd-music.ps1, go to the user's music folder
|
||||
cd-onedrive.ps1, go to the user's OneDrive folder
|
||||
cd-pics.ps1, go to the user's pictures folder
|
||||
cd-recycle-bin.ps1, go to the user's recycle bin folder
|
||||
cd-repos.ps1, go to the user's Git repositories folder
|
||||
cd-root.ps1, go to the root directory (C: on Windows)
|
||||
cd-scripts.ps1, go to the PowerShell Scripts folder
|
||||
cd-up.ps1, go one directory level up
|
||||
cd-up2.ps1, go two directory levels up
|
||||
cd-up3.ps1, go three directory levels up
|
||||
cd-up4.ps1, go four directory levels up
|
||||
cd-videos.ps1, go to the user's videos folder
|
||||
check-cpu-temp.ps1, checks the CPU temperature
|
||||
check-dns-resolution.ps1, checks the DNS resolution with frequently used domain names
|
||||
check-drive-space.ps1, checks the given drive for free space left
|
||||
check-file-system.ps1, checks the validity of the file system (needs admin rights)
|
||||
check-health.ps1, checks the system health
|
||||
check-ipv4-address.ps1, checks the given IPv4 address for validity
|
||||
check-ipv6-address.ps1, checks the given IPv6 address for validity
|
||||
check-mac-address.ps1, checks the given MAC address for validity
|
||||
check-ping.ps1, checks the ping latency to the internet
|
||||
check-swap-space.ps1, checks the swap space for free space left
|
||||
check-symlinks.ps1, checks every symlink in the given directory tree
|
||||
check-weather.ps1, checks the current weather for critical values
|
||||
check-windows-system-files.ps1, checks the validity of the Windows system files
|
||||
check-xml-file.ps1, checks the given XML file for validity
|
||||
cherry-picker.ps1, cherry-picks a Git commit into multiple branches
|
||||
clean-repo.ps1, cleans the current/given Git repository from untracked files (including submodules)
|
||||
clean-repos.ps1, cleans all Git repositories under the current/given directory from untracked files (including submodules)
|
||||
clear-recycle-bin.ps1, removes the content of the recycle bin folder (can not be undo!)
|
||||
clone-repos.ps1, clones well-known Git repositories
|
||||
close-calculator.ps1, closes the calculator program gracefully
|
||||
close-chrome.ps1, closes Google Chrome gracefully
|
||||
close-cortana.ps1, closes Cortana gracefully
|
||||
close-edge.ps1, closes Microsoft Edge gracefully
|
||||
close-file-explorer.ps1, closes Microsoft File Explorer gracefully
|
||||
close-program.ps1, closes the given program gracefully
|
||||
close-system-settings.ps1, closes the System Settings gracefully
|
||||
close-thunderbird.ps1, closes Mozilla Thunderbird gracefully
|
||||
close-vlc.ps1, closes the VLC media player gracefully
|
||||
close-windows-terminal.ps1, closes Windows Terminal gracefully
|
||||
configure-git.ps1, sets up the Git user configuration
|
||||
convert-csv2txt.ps1, converts the given CSV file into a text list
|
||||
convert-mysql2csv.ps1, converts the MySQL database table to a CSV file
|
||||
convert-ps2bat.ps1, converts PowerShell script(s) to .bat files
|
||||
convert-sql2csv.ps1, converts the SQL database table to a CSV file
|
||||
convert-txt2wav.ps1, converts text into a audio .WAV file
|
||||
create-branch.ps1, creates a new branch in the current/given Git repository
|
||||
create-shortcut.ps1, creates a shortcut
|
||||
create-symlink.ps1, creates a symbolic link
|
||||
create-tag.ps1, creates a new tag in the current/given Git repository
|
||||
daily-tasks.sh, execute PowerShell scripts automatically as daily tasks (Linux only)
|
||||
decrypt-file.ps1, decrypts the given file
|
||||
display-time.ps1, displays the current time for 10 seconds by default
|
||||
download-dir.ps1, downloads a directory tree from the given URL
|
||||
download-file.ps1, downloads a file from the given URL
|
||||
edit.ps1, edits the given file with the built-in text editor
|
||||
enable-crash-dumps.ps1, enables the writing of crash dumps
|
||||
enable-god-mode.ps1, enables the god mode (adds a new icon to the desktop)
|
||||
enable-ssh-client.ps1, enables the SSH client (needs admin rights)
|
||||
enable-ssh-server.ps1, enables the SSH server (needs admin rights)
|
||||
encrypt-file.ps1, encrypts the given file
|
||||
fetch-repo.ps1, fetches updates for the current/given Git repository (including submodules)
|
||||
fetch-repos.ps1, fetches updates for all Git repositories under the current/given directory (including submodules)
|
||||
generate-qrcode.ps1, generates a QR code
|
||||
hibernate.ps1, enables hibernate mode for the local computer (needs admin rights)
|
||||
inspect-exe.ps1, prints basic information of the given executable file
|
||||
install-google-chrome.ps1, installs the Google Chrome browser
|
||||
install-signal-cli.ps1, installs signal-cli from github.com/AsamK/signal-cli
|
||||
introduce-powershell.ps1, introduces PowerShell to new users
|
||||
list-aliases.ps1, lists all PowerShell aliases
|
||||
list-anagrams.ps1, lists all anagrams of the given word
|
||||
list-automatic-variables.ps1, lists the automatic variables of PowerShell
|
||||
list-branches.ps1, lists all branches in the current/given Git repository
|
||||
list-cheat-sheet.ps1, lists the PowerShell cheat sheet
|
||||
list-city-weather.ps1, lists the current weather of cities worldwide (east to west)
|
||||
list-commits.ps1, lists all commits in the current/given Git repository
|
||||
list-clipboard.ps1, lists the contents of the clipboard
|
||||
list-credits.ps1, shows the credits
|
||||
list-dir.ps1, lists the directory content (formatted in columns)
|
||||
list-dir-tree.ps1, lists the directory tree content
|
||||
list-drives.ps1, lists all drives
|
||||
list-environment-variables.ps1, lists all environment variables
|
||||
list-emojis.ps1, lists the emojis of Unicode 13.0
|
||||
list-empty-dirs.ps1, lists empty subfolders within the given directory tree
|
||||
list-empty-files.ps1, lists empty files within the given directory tree
|
||||
list-files.ps1, lists all files in the given folder and also in every subfolder
|
||||
list-fritzbox-calls.ps1, lists the FRITZ!Box calls
|
||||
list-fritzbox-devices.ps1, lists FRITZ!Box's known devices
|
||||
list-hidden-files.ps1, lists hidden files within the given directory tree
|
||||
list-installed-apps.ps1, lists the installed Windows Store apps
|
||||
list-installed-software.ps1, lists the installed software (except Windows Store apps)
|
||||
list-latest-tag.ps1, lists the latest tag on the current branch in a Git repository
|
||||
list-memos.ps1, lists the memos at $HOME/Memos.csv
|
||||
list-unused-files.ps1, lists unused files in a directory tree
|
||||
list-cmdlets.ps1, lists the PowerShell cmdlets
|
||||
list-earthquakes.ps1, lists earthquakes with magnitude >= 6.0 for the last 30 days
|
||||
list-modules.ps1, lists the PowerShell modules
|
||||
list-mysql-tables.ps1, lists the MySQL server tables
|
||||
list-network-shares.ps1, lists the network shares of the local computer
|
||||
list-news.ps1, lists the latest news
|
||||
list-os-releases.ps1, lists operating system releases and download URL
|
||||
list-os-updates.ps1, lists operating system updates
|
||||
list-printers.ps1, lists all printer known to the computer
|
||||
list-processes.ps1, lists the local computer processes
|
||||
list-profiles.ps1, lists your PowerShell profiles
|
||||
list-random-passwords.ps1, prints a list of random passwords
|
||||
list-random-pins.ps1, prints a list of random PIN's
|
||||
list-recycle-bin.ps1, lists the content of the recycle bin folder
|
||||
list-scripts.ps1, lists all PowerShell scripts in this repository
|
||||
list-services.ps1, lists the services on the local computer
|
||||
list-sql-tables.ps1, lists the SQL server tables
|
||||
list-submodules.ps1, lists the submodules of the current/given Git repository
|
||||
list-system-info.ps1, lists system information on the local computer
|
||||
list-tags.ps1, lists all tags in the current/given Git repository
|
||||
list-tasks.ps1, lists all Windows scheduler tasks
|
||||
list-timezone.ps1, lists the current time zone details
|
||||
list-timezones.ps1, lists all time zones available
|
||||
list-tiobe-index.ps1, lists the TIOBE index of top programming languages
|
||||
list-user-groups.ps1, lists the user groups on the local computer
|
||||
list-weather.ps1, lists the hourly weather
|
||||
list-workdir.ps1, lists the current working directory
|
||||
locate-city.ps1, prints the geographic location of the given city
|
||||
locate-ipaddress.ps1, prints the geographic location of the given IP address
|
||||
locate-zip-code.ps1, prints the geographic location of the given zip-code
|
||||
MD5.ps1, prints the MD5 checksum of the given file
|
||||
make-install.ps1, installs built executables and libs to the installation directory
|
||||
make-repo.ps1, builds the current/given Git repository
|
||||
make-repos.ps1, builds all Git repositories under the current/given directory
|
||||
moon.ps1, prints the current moon phase
|
||||
mute-audio.ps1, mutes audio
|
||||
next-joke.ps1], gets the next random Juck Norris joke
|
||||
open-browser.ps1, starts the default Web browser
|
||||
open-calculator.ps1, starts the calculator program
|
||||
open-email-client.ps1, starts the default email client
|
||||
open-file-explorer.ps1, starts the Microsoft File Explorer
|
||||
open-recycle-bin.ps1, starts the File Explorer with the recycle bin folder
|
||||
play-beep.ps1, plays a beep sound
|
||||
play-files.ps1, plays the given audio files
|
||||
play-mission-impossible.ps1, plays the Mission Impossible theme
|
||||
play-m3u.ps1, plays the given playlist (M3U file format)
|
||||
play-mp3.ps1, plays the given sound file (MP3 file format)
|
||||
play-super-mario.ps1, plays the Super Mario Intro
|
||||
play-the-imperial-march.ps1, plays the Imperial March (Star Wars)
|
||||
poweroff.ps1, halts the local computer (needs admin rights)
|
||||
pull-repo.ps1, pulls updates for the current/given Git repository (including submodules)
|
||||
pull-repos.ps1, pulls updates for all Git repositories under the current/given directory (including submodules)
|
||||
query-smart-data.ps1, queries the S.M.A.R.T. data of your HDD/SSD's and saves it to the current/given directory
|
||||
new-email.ps1, starts the default email client to write a new email
|
||||
reboot.ps1, reboots the local computer (needs admin rights)
|
||||
reboot-fritzbox.ps1, reboots the FRITZ!box device
|
||||
remove-empty-dirs.ps1, removes empty subfolders within the given directory tree
|
||||
search-filename.ps1, searches the directory tree for filenames by given pattern
|
||||
search-files.ps1, searches the given pattern in the given files
|
||||
scan-ports.ps1, scans the network for open/closed ports
|
||||
send-email.ps1, sends an email message
|
||||
send-tcp.ps1, sends a TCP message to the given IP address and port
|
||||
send-udp.ps1, sends a UDP datagram message to the given IP address and port
|
||||
set-profile.ps1, updates your PowerShell user profile
|
||||
set-timer.ps1, sets a timer for a countdown
|
||||
set-wallpaper.ps1, sets the given image as wallpaper
|
||||
SHA1.ps1, prints the SHA1 checksum of the given file
|
||||
SHA256.ps1, prints the SHA256 checksum of the given file
|
||||
simulate-matrix.ps1, simulates the Matrix (fun)
|
||||
simulate-presence.ps1, simulates the human presence against burglars
|
||||
speak-checklist.ps1, speaks the given checklist by text-to-speech (TTS)
|
||||
speak-countdown.ps1, starts a countdown by text-to-speech (TTS)
|
||||
speak-date.ps1, speaks the current date by text-to-speech (TTS)
|
||||
speak-english.ps1, speaks the given text with an English text-to-speech (TTS) voice
|
||||
speak-epub.ps1, speaks the content of the given Epub file by text-to-speech (TTS)
|
||||
speak-file.ps1, speaks the content of the given text file by text-to-speech (TTS)
|
||||
speak-german.ps1, speaks the given text with a German text-to-speech (TTS) voice
|
||||
speak-joke.ps1, speaks the next joke by text-to-speech (TTS)
|
||||
speak-test.ps1, performs a speak test by text-to-speech (TTS)
|
||||
speak-text.ps1, speaks the given text by text-to-speech (TTS)
|
||||
speak-time.ps1, speaks the current time by text-to-speech (TTS)
|
||||
start-ipfs-server.ps1, starts a local IPFS server
|
||||
switch-branch.ps1, switches the branch in the current/given Git repository (including submodules)
|
||||
switch-shelly1.ps1, switches a Shelly1 device in the local network
|
||||
sync-repo.ps1, synchronizes a Git repository by push & pull (including submodules)
|
||||
take-screenshot.ps1, takes a single screenshot
|
||||
take-screenshots.ps1, takes multiple screenshots
|
||||
translate-file.ps1, translates the given text file into another language
|
||||
translate-files.ps1, translates the given text files into any supported language
|
||||
translate-text.ps1, translates the given text into other languages
|
||||
turn-volume-up.ps1, turns the audio volume up (+10% by default)
|
||||
turn-volume-down.ps1, turns the audio volume down (-10% by default)
|
||||
unmute-audio.ps1, unmutes audio
|
||||
upload-file.ps1, uploads the local file to the given FTP server
|
||||
voice-control.ps1, executes the PowerShell scripts by voice
|
||||
wakeup.ps1, sends a magic packet to the given computer, waking him up
|
||||
weather.ps1, prints the current weather forecast
|
||||
weather-report.ps1, prints the local weather report
|
||||
what-is.ps1, prints a description of the given abbreviation
|
||||
write-animated.ps1, writes animated text
|
||||
write-big.ps1, writes the given text in big letters
|
||||
write-blue.ps1, writes the given text in a blue foreground color
|
||||
write-braille.ps1, writes the given text in Braille
|
||||
write-green.ps1, writes the given text in a green foreground color
|
||||
write-lowercase.ps1, writes the given text in lowercase letters
|
||||
write-marquee.ps1, writes the given text as marquee
|
||||
write-morse-code.ps1, writes the given text in Morse code
|
||||
write-motd.ps1, writes the message of the day (MOTD)
|
||||
write-red.ps1, writes the given text in a red foreground color
|
||||
write-rot13.ps1, encodes or decodes the given text with ROT13
|
||||
write-typewriter.ps1, writes the given text with the typewriter effect
|
||||
write-uppercase.ps1, writes the given text in uppercase letters
|
||||
write-vertical.ps1, writes the given text in vertical direction
|
||||
zip-dir.ps1, creates a zip archive of the given directory
|
||||
|
21
Powershell/Data/wordcities-license.txt
Normal file
21
Powershell/Data/wordcities-license.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
This license is a legal document designed to protect your rights and the rights of the Pareto Software, LLC, the owner of Simplemaps.com. Please read it carefully. Purchasing or downloading a data product constitutes acceptance of this license.
|
||||
|
||||
Description of Product and Parties: This license is a contract between you (hereafter, the Customer) and Pareto Software, LLC (hereafter, the Provider) regarding the use and/or sale of an collection of geographic data (hereafter, the Database).
|
||||
|
||||
Ownership of Database: All rights to the Database are owned by the Provider. The Database is a cleaned and curated collection of geographic facts and the Provider retains all rights to the Database afforded by the law. Ownership of any intellectual property generated by the Provider while performing custom modifications to the Database for a Customer (with or without payment) is retained by the Provider.
|
||||
|
||||
License: Customers who purchase a license are allowed to use the database for projects that benefit their organization or that their organization oversees. Attribution is not required. The Customer is allowed to query the database to power privately or publicly facing applications. The Customer is allowed to make copies and backups of the data. The Customer may not publicly redistribute the Database without prior written permission. Customers can transfer their license to a third-party, at the sole discretion of the Provider, by submitting a request via email.
|
||||
|
||||
Free US Zip Code Database: The Provider offers a free version of the US Zip Code Database. This Database is offered free of charge conditional on a link back to https://simplemaps.com/data/us-zips. This backlink must come from a public webpage where the Customer is using the data. If the Customer uses the data internally, the backlink must be placed on the organization's website on a page that can be easily found though links on the root domain. The link must be clearly visible to the human eye. The backlink must be placed before the Customer uses the Database in production.
|
||||
|
||||
Free US Cities Database: The Provider offers a free version of the US Cities Database. This Database is offered free of charge conditional on a link back to https://simplemaps.com/data/us-cities. This backlink must come from a public webpage where the Customer is using the data. If the Customer uses the data internally, the backlink must be placed on the organization's website on a page that can be easily found though links on the root domain. The link must be clearly visible to the human eye. The backlink must be placed before the Customer uses the Database in production.
|
||||
|
||||
Basic World Cities Database: The Provider offers a Basic World Cities Database free of charge. This database is licensed under the Creative Commons Attribution 4.0 license as described at: https://creativecommons.org/licenses/by/4.0/.
|
||||
|
||||
Comprehensive and Pro World Cities Database Density Data: The Comprehensive and Pro World Cities Databases includes density estimates from The Center for International Earth Science Information Network - CIESIN - Columbia University. 2016. Gridded Population of the World, Version 4 (GPWv4): Population Count. Palisades, NY: NASA Socioeconomic Data and Applications Center (SEDAC). http://dx.doi.org/10.7927/H4X63JVC. Accessed June 2017. The density estimates are include under the Creative Commons Attribution 4.0 International License. The Provider places no additional restrictions on the use or distribution of the density data.
|
||||
|
||||
Guarantee: The Provider guarantees that for the period of thirty (30) days from the purchase of a License that the Customer shall, upon request, be refunded their actual purchase price within a reasonable period of time. The Customer acknowledges that receipt of a refund constitutes a termination of their License to use the Database. In the event of a Refund, the Customer promises to delete the Database immediately. Refunds after the period of thirty (30) days shall be at the sole discretion of the Provider.
|
||||
|
||||
LIMITATION OF LIABILITY: THE DATABASE IS SOLD "AS IS" AND "WITH ALL FAULTS". THE PROVIDER MAKES NO WARRANTY THAT IT IS FREE OF DEFECTS OR IS SUITABLE FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL THE PROVIDER BE RESPONSIBLE FOR LOSS OR DAMAGES ARRISING FROM THE INSTALLATION OR USE OF THE DATABASE, INCLUDING BUT NOT LIMITED TO ANY INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES. THE CUSTOMER IS SOLELY RESPONSIBLE FOR ENSURING THAT THEIR USE OF THE DATABASE IS IN ACCORDANCE WITH THE LAW OF THEIR JURISDICTION.
|
||||
|
||||
PROHIBITION OF ILLEGAL USE: USE OF THE DATABASE WHICH IS CONTRARY TO THE LAW IS PROHIBITED, AND IMMEDIATELY TERMINATES THE CUSTOMER'S LICENSE TO USE THE DATABASE.
|
||||
26563
Powershell/Data/worldcities.csv
Normal file
26563
Powershell/Data/worldcities.csv
Normal file
File diff suppressed because it is too large
Load Diff
1129901
Powershell/Data/zip-codes.csv
Normal file
1129901
Powershell/Data/zip-codes.csv
Normal file
File diff suppressed because it is too large
Load Diff
4
Powershell/From Evernote/Connect_To_365.ps1
Normal file
4
Powershell/From Evernote/Connect_To_365.ps1
Normal file
@@ -0,0 +1,4 @@
|
||||
Set-ExecutionPolicy RemoteSigned
|
||||
$UserCredential = Get-Credential
|
||||
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
|
||||
Import-PSSession $Session
|
||||
1
Powershell/From Evernote/Disconnect_From_365.ps1
Normal file
1
Powershell/From Evernote/Disconnect_From_365.ps1
Normal file
@@ -0,0 +1 @@
|
||||
Remove-PSSession $Session
|
||||
@@ -0,0 +1,487 @@
|
||||
@echo off
|
||||
cls
|
||||
echo.
|
||||
ECHO ===============================================================================
|
||||
echo Paste or write the complete path to install.esd or install.wim file
|
||||
echo ^(without quotes marks "" even if the path contains spaces^)
|
||||
ECHO ===============================================================================
|
||||
echo.
|
||||
set /p WIMFILE=
|
||||
if "%WIMFILE%"=="" echo Incorrect file name or path&echo.&PAUSE&GOTO :QUIT
|
||||
|
||||
title ESD ^<^> WIM
|
||||
color 1f
|
||||
%windir%\system32\reg.exe query "HKU\S-1-5-19" >nul 2>&1 || (
|
||||
echo -------
|
||||
echo *** WARNING ***
|
||||
echo -------
|
||||
echo.
|
||||
echo.
|
||||
echo ADMINISTRATOR PRIVILEGES NOT DETECTED
|
||||
echo ____________________________________________________________________________
|
||||
echo.
|
||||
echo This script require administrator privileges.
|
||||
echo.
|
||||
echo To do so, right click on this script and select 'Run as administrator'
|
||||
echo.
|
||||
echo.
|
||||
echo.
|
||||
echo Press any key to exit...
|
||||
pause >nul
|
||||
goto :eof
|
||||
)
|
||||
cd /d "%~dp0"
|
||||
if exist "%CD%\dism\dism.exe" set Path=%CD%\dism;%Path%
|
||||
SET ERRORTEMP=
|
||||
set /A count=0
|
||||
|
||||
dism /get-wiminfo /wimfile:"%WIMFILE%" >nul 2>&1 || (
|
||||
echo.
|
||||
echo Incorrect file name or path
|
||||
echo.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
goto :eof
|
||||
)
|
||||
setlocal EnableDelayedExpansion
|
||||
FOR /F "tokens=2 delims=: " %%i IN ('dism /english /Get-WimInfo /WimFile:"%WIMFILE%" ^| findstr "Index"') DO SET images=%%i
|
||||
for /L %%i in (1, 1, %images%) do call :setcount %%i
|
||||
|
||||
if "%WIMFILE:~-3%"=="esd" GOTO :ESDMENU
|
||||
if "%WIMFILE:~-3%"=="wim" GOTO :WIMMENU
|
||||
exit
|
||||
|
||||
:setcount
|
||||
set /A count+=1
|
||||
for /f "tokens=1* delims=: " %%i in ('dism /english /get-wiminfo /wimfile:"%WIMFILE%" /index:%1 ^| find /i "Name"') do set name%count%="%%j"
|
||||
goto :eof
|
||||
|
||||
:ESDMENU
|
||||
cls
|
||||
ECHO ===============================================================================
|
||||
ECHO. Detected ESD file contains %images% indexes:
|
||||
ECHO.
|
||||
for /L %%i in (1, 1, %images%) do (
|
||||
ECHO. %%i. !name%%i!
|
||||
)
|
||||
ECHO.
|
||||
ECHO ===============================================================================
|
||||
ECHO. Options:
|
||||
ECHO ===============================================================================
|
||||
ECHO. 1 - Export 1st index
|
||||
ECHO. 2 - Export all indexes
|
||||
ECHO. 3 - Export selected single index
|
||||
ECHO. 4 - Export selected range of indexes
|
||||
ECHO ===============================================================================
|
||||
ECHO. Press 'Q' to Quit
|
||||
ECHO ===============================================================================
|
||||
|
||||
choice /c 1234q /n /m "Choose a menu option, or Q to quit: "
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP%==1 GOTO :ESD1
|
||||
IF %ERRORTEMP%==2 GOTO :ESD2
|
||||
IF %ERRORTEMP%==3 GOTO :ESD3
|
||||
IF %ERRORTEMP%==4 GOTO :ESD4
|
||||
IF %ERRORTEMP%==5 GOTO :QUIT
|
||||
GOTO :MAINMENU
|
||||
|
||||
:ESD1
|
||||
cls
|
||||
IF EXIST "%CD%\install.wim" (
|
||||
ECHO ===============================================================================
|
||||
ECHO. An install.wim file is already present in the current folder.
|
||||
ECHO ===============================================================================
|
||||
ECHO.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
)
|
||||
ECHO ===============================================================================
|
||||
Echo Exporting ESD Index 1 to a new install.wim file...
|
||||
ECHO ===============================================================================
|
||||
mkdir temp
|
||||
dism /Quiet /Capture-Image /ImageFile:install.wim /CaptureDir:.\temp /Name:container /Compress:max /CheckIntegrity
|
||||
rmdir /s /q temp
|
||||
dism /Export-Image /SourceImageFile:"%WIMFILE%" /SourceIndex:1 /DestinationImageFile:install.wim /compress:recovery /CheckIntegrity
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP% NEQ 0 (ECHO.&Echo Errors were reported during dism export.&PAUSE&GOTO :QUIT)
|
||||
dism /Quiet /Delete-Image /ImageFile:install.wim /Index:1 /CheckIntegrity
|
||||
echo.
|
||||
echo Done.
|
||||
echo.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
|
||||
:ESD2
|
||||
cls
|
||||
IF EXIST "%CD%\install.wim" (
|
||||
ECHO ===============================================================================
|
||||
ECHO. An install.wim file is already present in the current folder.
|
||||
ECHO ===============================================================================
|
||||
ECHO.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
)
|
||||
ECHO ===============================================================================
|
||||
Echo Exporting ESD Index 1 to a new install.wim file...
|
||||
ECHO ===============================================================================
|
||||
mkdir temp
|
||||
dism /Quiet /Capture-Image /ImageFile:install.wim /CaptureDir:.\temp /Name:container /Compress:max /CheckIntegrity
|
||||
rmdir /s /q temp
|
||||
dism /Export-Image /SourceImageFile:"%WIMFILE%" /SourceIndex:1 /DestinationImageFile:install.wim /compress:recovery /CheckIntegrity
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP% NEQ 0 (ECHO.&Echo Errors were reported during dism export.&PAUSE&GOTO :QUIT)
|
||||
dism /Quiet /Delete-Image /ImageFile:install.wim /Index:1 /CheckIntegrity
|
||||
|
||||
if "%images%"=="1" (
|
||||
echo.
|
||||
echo Done.
|
||||
echo.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
)
|
||||
|
||||
for /L %%i in (2, 1, %images%) do (
|
||||
ECHO.
|
||||
ECHO ===============================================================================
|
||||
Echo Exporting ESD Index %%i to install.wim file...
|
||||
ECHO ===============================================================================
|
||||
dism /Export-Image /SourceImageFile:"%WIMFILE%" /SourceIndex:%%i /DestinationImageFile:install.wim /compress:recovery /CheckIntegrity
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP% NEQ 0 (ECHO.&Echo Errors were reported during dism export.&PAUSE&GOTO :QUIT)
|
||||
)
|
||||
echo.
|
||||
echo Done.
|
||||
echo.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
|
||||
:ESD3
|
||||
cls
|
||||
set _index=
|
||||
ECHO ===============================================================================
|
||||
ECHO. Detected ESD file contains %images% indexes:
|
||||
ECHO.
|
||||
for /L %%i in (1, 1, %images%) do (
|
||||
ECHO. %%i. !name%%i!
|
||||
)
|
||||
ECHO.
|
||||
ECHO ===============================================================================
|
||||
ECHO. Enter desired index number to export
|
||||
ECHO ===============================================================================
|
||||
ECHO. Enter zero '0' to go back to Main Menu
|
||||
ECHO ===============================================================================
|
||||
set /p _index= ^>
|
||||
if /i "%_index%"=="0" goto :ESDMENU
|
||||
if [%_index%]==[] goto :ESD3
|
||||
if /i %_index% GTR %images% echo.&echo Selected number is higher than available indexes&echo.&PAUSE&goto :ESD3
|
||||
|
||||
cls
|
||||
IF EXIST "%CD%\install.wim" (
|
||||
ECHO ===============================================================================
|
||||
ECHO. An install.wim file is already present in the current folder.
|
||||
ECHO ===============================================================================
|
||||
ECHO.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
)
|
||||
ECHO ===============================================================================
|
||||
Echo Exporting ESD Index %_index% to a new install.wim file...
|
||||
ECHO ===============================================================================
|
||||
mkdir temp
|
||||
dism /Quiet /Capture-Image /ImageFile:install.wim /CaptureDir:.\temp /Name:container /Compress:max /CheckIntegrity
|
||||
rmdir /s /q temp
|
||||
dism /Export-Image /SourceImageFile:"%WIMFILE%" /SourceIndex:%_index% /DestinationImageFile:install.wim /compress:recovery /CheckIntegrity
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP% NEQ 0 (ECHO.&Echo Errors were reported during dism export.&PAUSE&GOTO :QUIT)
|
||||
dism /Quiet /Delete-Image /ImageFile:install.wim /Index:1 /CheckIntegrity
|
||||
echo.
|
||||
echo Done.
|
||||
echo.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
|
||||
:ESD4
|
||||
cls
|
||||
set _range=
|
||||
set _start=
|
||||
set _end=
|
||||
ECHO ===============================================================================
|
||||
ECHO. Detected ESD file contains %images% indexes:
|
||||
ECHO.
|
||||
for /L %%i in (1, 1, %images%) do (
|
||||
ECHO. %%i. !name%%i!
|
||||
)
|
||||
ECHO.
|
||||
ECHO ===============================================================================
|
||||
ECHO. Enter desired Range of indexes to export: Start-End
|
||||
ECHO. Example: 2-4 or 1-3 or 3-4
|
||||
ECHO ===============================================================================
|
||||
ECHO. Enter zero '0' to go back to Main Menu
|
||||
ECHO ===============================================================================
|
||||
set /p _range= ^>
|
||||
if /i "%_range%"=="0" goto :ESDMENU
|
||||
if [%_range%]==[] goto :ESD4
|
||||
for /f "tokens=1 delims=-" %%i in ('echo %_range%') do set _start=%%i
|
||||
for /f "tokens=2 delims=-" %%i in ('echo %_range%') do set _end=%%i
|
||||
if /i %_start% GTR %images% echo.&echo Range Start is higher than available indexes&echo.&PAUSE&goto :ESD4
|
||||
if /i %_end% GTR %images% echo.&echo Range End is higher than available indexes&echo.&PAUSE&goto :ESD4
|
||||
if /i %_start% EQU %_end% echo.&echo Range Start and End are equal. Use option 3 of main menu to export single index&echo.&PAUSE&goto :ESDMENU
|
||||
|
||||
cls
|
||||
IF EXIST "%CD%\install.wim" (
|
||||
ECHO ===============================================================================
|
||||
ECHO. An install.wim file is already present in the current folder.
|
||||
ECHO ===============================================================================
|
||||
ECHO.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
)
|
||||
ECHO ===============================================================================
|
||||
Echo Exporting ESD Index %_start% to a new install.wim file...
|
||||
ECHO ===============================================================================
|
||||
mkdir temp
|
||||
dism /Quiet /Capture-Image /ImageFile:install.wim /CaptureDir:.\temp /Name:container /Compress:max /CheckIntegrity
|
||||
rmdir /s /q temp
|
||||
dism /Export-Image /SourceImageFile:"%WIMFILE%" /SourceIndex:%_start% /DestinationImageFile:install.wim /compress:recovery /CheckIntegrity
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP% NEQ 0 (ECHO.&Echo Errors were reported during dism export.&PAUSE&GOTO :QUIT)
|
||||
dism /Quiet /Delete-Image /ImageFile:install.wim /Index:1 /CheckIntegrity
|
||||
|
||||
set /a _start+=1
|
||||
for /L %%i in (%_start%, 1, %_end%) do (
|
||||
ECHO.
|
||||
ECHO ===============================================================================
|
||||
Echo Exporting ESD Index %%i to install.wim file...
|
||||
ECHO ===============================================================================
|
||||
dism /Export-Image /SourceImageFile:"%WIMFILE%" /SourceIndex:%%i /DestinationImageFile:install.wim /compress:recovery /CheckIntegrity
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP% NEQ 0 (ECHO.&Echo Errors were reported during dism export.&PAUSE&GOTO :QUIT)
|
||||
)
|
||||
echo.
|
||||
echo Done.
|
||||
echo.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
|
||||
:WIMMENU
|
||||
cls
|
||||
ECHO ===============================================================================
|
||||
ECHO. Detected WIM file contains %images% indexes:
|
||||
ECHO.
|
||||
for /L %%i in (1, 1, %images%) do (
|
||||
ECHO. %%i. !name%%i!
|
||||
)
|
||||
ECHO.
|
||||
ECHO ===============================================================================
|
||||
ECHO. Options:
|
||||
ECHO ===============================================================================
|
||||
ECHO. 1 - Export 1st index
|
||||
ECHO. 2 - Export all indexes
|
||||
ECHO. 3 - Export selected single index
|
||||
ECHO. 4 - Export selected range of indexes
|
||||
ECHO ===============================================================================
|
||||
ECHO. Press 'Q' to Quit
|
||||
ECHO ===============================================================================
|
||||
|
||||
choice /c 1234q /n /m "Choose a menu option, or Q to quit: "
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP%==1 GOTO :WIM1
|
||||
IF %ERRORTEMP%==2 GOTO :WIM2
|
||||
IF %ERRORTEMP%==3 GOTO :WIM3
|
||||
IF %ERRORTEMP%==4 GOTO :WIM4
|
||||
IF %ERRORTEMP%==5 GOTO :QUIT
|
||||
GOTO :MAINMENU
|
||||
|
||||
:WIM1
|
||||
cls
|
||||
IF EXIST "%CD%\install.esd" (
|
||||
ECHO ===============================================================================
|
||||
ECHO. An install.esd file is already present in the current folder.
|
||||
ECHO ===============================================================================
|
||||
ECHO.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
)
|
||||
ECHO ===============================================================================
|
||||
Echo Exporting WIM Index 1 to a new install.esd file...
|
||||
ECHO ===============================================================================
|
||||
echo.
|
||||
echo *** This will require some time, high CPU and Disk usage, please be patient ***
|
||||
echo.
|
||||
dism /export-image /sourceimagefile:"%WIMFILE%" /Sourceindex:1 /destinationimagefile:install.esd /compress:recovery /checkintegrity
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP% NEQ 0 (ECHO.&Echo Errors were reported during dism export.&PAUSE&GOTO :QUIT)
|
||||
echo.
|
||||
echo Done.
|
||||
echo.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
|
||||
:WIM2
|
||||
cls
|
||||
IF EXIST "%CD%\install.esd" (
|
||||
ECHO ===============================================================================
|
||||
ECHO. An install.esd file is already present in the current folder.
|
||||
ECHO ===============================================================================
|
||||
ECHO.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
)
|
||||
ECHO ===============================================================================
|
||||
Echo Exporting WIM Index 1 to a new install.esd file...
|
||||
ECHO ===============================================================================
|
||||
echo.
|
||||
echo *** This will require some time, high CPU and Disk usage, please be patient ***
|
||||
echo.
|
||||
dism /Export-Image /SourceImageFile:"%WIMFILE%" /Sourceindex:1 /DestinationImageFile:install.esd /compress:recovery /CheckIntegrity
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP% NEQ 0 (ECHO.&Echo Errors were reported during dism export.&PAUSE&GOTO :QUIT)
|
||||
|
||||
if "%images%"=="1" (
|
||||
echo.
|
||||
echo Done.
|
||||
echo.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
)
|
||||
|
||||
for /L %%i in (2, 1, %images%) do (
|
||||
ECHO.
|
||||
ECHO ===============================================================================
|
||||
Echo Exporting WIM Index %%i to install.esd file...
|
||||
ECHO ===============================================================================
|
||||
dism /Export-Image /SourceImageFile:"%WIMFILE%" /SourceIndex:%%i /DestinationImageFile:install.esd /compress:recovery /CheckIntegrity
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP% NEQ 0 (ECHO.&Echo Errors were reported during dism export.&PAUSE&GOTO :QUIT)
|
||||
)
|
||||
echo.
|
||||
echo Done.
|
||||
echo.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
|
||||
:WIM3
|
||||
cls
|
||||
set _index=
|
||||
ECHO ===============================================================================
|
||||
ECHO. Detected WIM file contains %images% indexes:
|
||||
ECHO.
|
||||
for /L %%i in (1, 1, %images%) do (
|
||||
ECHO. %%i. !name%%i!
|
||||
)
|
||||
ECHO.
|
||||
ECHO ===============================================================================
|
||||
ECHO. Enter desired index number to export
|
||||
ECHO ===============================================================================
|
||||
ECHO. Enter zero '0' to go back to Main Menu
|
||||
ECHO ===============================================================================
|
||||
set /p _index= ^>
|
||||
if /i "%_index%"=="0" goto :WIMMENU
|
||||
if [%_index%]==[] goto :WIM3
|
||||
if /i %_index% GTR %images% echo.&echo Selected number is higher than available indexes&echo.&PAUSE&goto :WIM3
|
||||
|
||||
cls
|
||||
IF EXIST "%CD%\install.esd" (
|
||||
ECHO ===============================================================================
|
||||
ECHO. An install.esd file is already present in the current folder.
|
||||
ECHO ===============================================================================
|
||||
ECHO.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
)
|
||||
ECHO ===============================================================================
|
||||
Echo Exporting WIM Index %_index% to a new install.esd file...
|
||||
ECHO ===============================================================================
|
||||
echo.
|
||||
echo *** This will require some time, high CPU and Disk usage, please be patient ***
|
||||
echo.
|
||||
dism /Export-Image /SourceImageFile:"%WIMFILE%" /SourceIndex:%_index% /DestinationImageFile:install.esd /compress:recovery /CheckIntegrity
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP% NEQ 0 (ECHO.&Echo Errors were reported during dism export.&PAUSE&GOTO :QUIT)
|
||||
echo.
|
||||
echo Done.
|
||||
echo.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
|
||||
:WIM4
|
||||
cls
|
||||
set _range=
|
||||
set _start=
|
||||
set _end=
|
||||
ECHO ===============================================================================
|
||||
ECHO. Detected WIM file contains %images% indexes:
|
||||
ECHO.
|
||||
for /L %%i in (1, 1, %images%) do (
|
||||
ECHO. %%i. !name%%i!
|
||||
)
|
||||
ECHO.
|
||||
ECHO ===============================================================================
|
||||
ECHO. Enter desired Range of indexes to export: Start-End
|
||||
ECHO. Example: 2-4 or 1-3 or 3-4
|
||||
ECHO ===============================================================================
|
||||
ECHO. Enter zero '0' to go back to Main Menu
|
||||
ECHO ===============================================================================
|
||||
set /p _range= ^>
|
||||
if /i "%_range%"=="0" goto :WIMMENU
|
||||
if [%_range%]==[] goto :WIM4
|
||||
for /f "tokens=1 delims=-" %%i in ('echo %_range%') do set _start=%%i
|
||||
for /f "tokens=2 delims=-" %%i in ('echo %_range%') do set _end=%%i
|
||||
if /i %_start% GTR %images% echo.&echo Range Start is higher than available indexes&echo.&PAUSE&goto :WIM4
|
||||
if /i %_end% GTR %images% echo.&echo Range End is higher than available indexes&echo.&PAUSE&goto :WIM4
|
||||
if /i %_start% EQU %_end% echo.&echo Range Start and End are equal. Use option 3 of main menu to export single index&echo.&PAUSE&goto :WIMMENU
|
||||
|
||||
cls
|
||||
IF EXIST "%CD%\install.esd" (
|
||||
ECHO ===============================================================================
|
||||
ECHO. An install.esd file is already present in the current folder.
|
||||
ECHO ===============================================================================
|
||||
ECHO.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
)
|
||||
ECHO ===============================================================================
|
||||
Echo Exporting WIM Index %_start% to a new install.esd file...
|
||||
ECHO ===============================================================================
|
||||
echo.
|
||||
echo *** This will require some time, high CPU and Disk usage, please be patient ***
|
||||
echo.
|
||||
dism /Export-Image /SourceImageFile:"%WIMFILE%" /SourceIndex:%_start% /DestinationImageFile:install.esd /compress:recovery /CheckIntegrity
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP% NEQ 0 (ECHO.&Echo Errors were reported during dism export.&PAUSE&GOTO :QUIT)
|
||||
|
||||
set /a _start+=1
|
||||
for /L %%i in (%_start%, 1, %_end%) do (
|
||||
ECHO.
|
||||
ECHO ===============================================================================
|
||||
Echo Exporting WIM Index %%i to install.esd file...
|
||||
ECHO ===============================================================================
|
||||
dism /Export-Image /SourceImageFile:"%WIMFILE%" /SourceIndex:%%i /DestinationImageFile:install.esd /compress:recovery /CheckIntegrity
|
||||
SET ERRORTEMP=%ERRORLEVEL%
|
||||
IF %ERRORTEMP% NEQ 0 (ECHO.&Echo Errors were reported during dism export.&PAUSE&GOTO :QUIT)
|
||||
)
|
||||
echo.
|
||||
echo Done.
|
||||
echo.
|
||||
echo Press any key to exit.
|
||||
pause >nul
|
||||
GOTO :QUIT
|
||||
|
||||
:QUIT
|
||||
267
Powershell/From Evernote/Intune.ps1
Normal file
267
Powershell/From Evernote/Intune.ps1
Normal file
@@ -0,0 +1,267 @@
|
||||
param([switch]$Elevated)
|
||||
function Check-Admin {
|
||||
$currentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())
|
||||
$currentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
|
||||
}
|
||||
if ((Check-Admin) -eq $false) {
|
||||
if ($elevated)
|
||||
{
|
||||
# could not elevate, quit
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
Start-Process powershell.exe -Verb RunAs -ArgumentList ('-noprofile -noexit -file "{0}" -elevated' -f ($myinvocation.MyCommand.Definition))
|
||||
}
|
||||
exit
|
||||
}
|
||||
function Write-ProgressHelper {
|
||||
param (
|
||||
[int]$StepNumber,
|
||||
[string]$Message
|
||||
)
|
||||
|
||||
Write-Progress -Activity 'PSC Update Readiness 2019' -Status $Message -PercentComplete (($StepNumber / $steps) * 100)
|
||||
}
|
||||
|
||||
$script:steps = ([System.Management.Automation.PsParser]::Tokenize((gc "$PSScriptRoot\$($MyInvocation.MyCommand.Name)"), [ref]$null) | where { $_.Type -eq 'Command' -and $_.Content -eq 'Write-ProgressHelper' }).Count
|
||||
|
||||
$stepCounter = 0
|
||||
|
||||
Write-ProgressHelper -Message 'Checking For Previous Run' -StepNumber ($stepCounter++)
|
||||
Start-Sleep -Seconds 2.5
|
||||
$ErrorActionPreference="SilentlyContinue"
|
||||
$maxRepeat = 10
|
||||
$Organisation = "PSC"
|
||||
$ThisPC = ($env:COMPUTERNAME + $env:username)
|
||||
$freespaceError = ("$env:COMPUTERNAME only has $spacegb GB Free and cannot continue 1903 install")
|
||||
$TeamViewerFileName = "c:\teamviewer_install\TeamviewerHost.msi"
|
||||
$InTuneLog = "c:\InTune_Log\$env:COMPUTERNAME.log"
|
||||
$InTuneFolder = "c:\InTune_Log\*.*"
|
||||
$InTune_Folder = "c:\InTune_Log\"
|
||||
$ts = New-TimeSpan -Hours 2
|
||||
function not-exist { -not (Test-Path -Path $TeamViewerFileName) }
|
||||
#Set-Alias !exist not-exist -Option "Constant, AllScope"
|
||||
#Set-Alias exist Test-Path -Option "Constant, AllScope"
|
||||
Add-Type -AssemblyName System.Windows.Forms | Out-Null
|
||||
Stop-Transcript | out-null
|
||||
$ErrorActionPreference = "Continue"
|
||||
If (-not(Test-Path -Path $InTune_Folder)) {
|
||||
mkdir $InTune_Folder }
|
||||
filter timestamp {"$(Get-Date -Format G): $_"}
|
||||
|
||||
if (Test-Path -Path $InTuneLog) {
|
||||
Remove-Item $InTuneLog -ErrorAction SilentlyContinue
|
||||
Remove-Item $InTune_Folder\$env:COMPUTERNAME.zip -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item c:\InTune_Log\"$env:COMPUTERNAME"_Transcript.log -ErrorAction SilentlyContinue
|
||||
Remove-Item c:\InTune_Log\"$env:COMPUTERNAME".csv -ErrorAction SilentlyContinue
|
||||
Remove-Item c:\InTune_Log\$env:Computername-Bitlocker-Recovery-key.txt -ErrorAction SilentlyContinue
|
||||
Start-Sleep -Seconds 1.5}
|
||||
Else
|
||||
{
|
||||
# Move On
|
||||
}
|
||||
Start-Transcript -path c:\InTune_Log\"$env:COMPUTERNAME"_Transcript.log
|
||||
Write-ProgressHelper -Message 'Checking For Teamviewer' -StepNumber ($stepCounter++)
|
||||
Start-Sleep -Seconds 2.5
|
||||
############################################################################
|
||||
# Teamviewer Start
|
||||
############################################################################
|
||||
#Get Teamviewer
|
||||
if (-not (Test-Path -Path $TeamViewerFileName)) {
|
||||
mkdir c:\teamviewer_install
|
||||
$url = "https://onedrive.live.com/download?cid=77FB0E4F642F10B7&resid=77FB0E4F642F10B7%21273176&authkey=AOouFE3GDGRSHIc"
|
||||
$output = "c:\teamviewer_install\TeamviewerHost.msi"
|
||||
$start_time = Get-Date
|
||||
|
||||
$wc = New-Object System.Net.WebClient
|
||||
$wc.DownloadFile($url, $output)
|
||||
Write-Host "Temaviewer Downloaded"
|
||||
msiexec.exe /i "c:\teamviewer_install\TeamviewerHost.msi" /qn CUSTOMCONFIGID=6988pev APITOKEN=6581446-B1aEz7nIk9k92p4G7C1R ASSIGNMENTOPTIONS="--grant-easy-access"
|
||||
Write-Host "Teamviewer Installed"
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Host "TeamViewer Already Installed"
|
||||
}
|
||||
|
||||
#############################################################################
|
||||
# Teamviewer End
|
||||
#############################################################################
|
||||
Write-ProgressHelper -Message 'Checking Your PC Integrity - Integrity Is Important You Know' -StepNumber ($stepCounter++)
|
||||
Start-Sleep -Seconds 5
|
||||
##############################################################################
|
||||
# Computer Sanity Check End
|
||||
##############################################################################
|
||||
|
||||
# Power Connect Check
|
||||
|
||||
#Function Check-BatteryState {
|
||||
#param($Laptop=$env:computername)
|
||||
#$Bstatus = ((Get-WmiObject -Class Win32_Battery).BatteryStatus)
|
||||
#}
|
||||
$Bstatus = ((Get-WmiObject -Class Win32_Battery).BatteryStatus)
|
||||
if($Bstatus) {
|
||||
switch ($Bstatus)
|
||||
{
|
||||
1 { "Battery is discharging" }
|
||||
2 { "The system has access to AC so no battery is being discharged. However, the battery is not necessarily charging." }
|
||||
3 { "Fully Charged" }
|
||||
4 { "Low" }
|
||||
5 { "Critical" }
|
||||
6 { "Charging" }
|
||||
7 { "Charging and High" }
|
||||
8 { "Charging and Low" }
|
||||
9 { "Charging and Critical " }
|
||||
10 { "Unknown State" }
|
||||
11 { "Partially Charged" }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
If ($BStatus -eq 2) {
|
||||
# Move On
|
||||
}
|
||||
|
||||
Else {
|
||||
[System.Windows.Forms.MessageBox]::Show("You Need To Be Connected To The Power Adapter! Please re run from Software Center when power is avalable. Exiting...", $Organisation,
|
||||
[System.Windows.Forms.MessageBoxButtons]::OK,
|
||||
[System.Windows.Forms.MessageBoxIcon]::ERROR)
|
||||
|
||||
}
|
||||
|
||||
|
||||
# Power Connect Check End
|
||||
#----------------------------------------------------------------------------
|
||||
Write-ProgressHelper -Message 'Checking Your Free Drive Space - You Should Be Saving Everything To The Cloud Anyway' -StepNumber ($stepCounter++)
|
||||
Start-Sleep -Seconds 5
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Free Space Check Start
|
||||
|
||||
$disk = Get-WMIObject Win32_Logicaldisk -filter "deviceid='$((Get-WMIObject Win32_OperatingSystem -computername $env:COMPUTERNAME).systemdrive)'" -ComputerName $env:COMPUTERNAME
|
||||
$freespace = ($disk.FreeSpace)
|
||||
$spacegb = [math]::Round($disk.Freespace/1GB,2)
|
||||
|
||||
# Free Space Check End
|
||||
#----------------------------------------------------------------------------
|
||||
Write-ProgressHelper -Message 'Checking Your PC Is Secure - Safety First!' -StepNumber ($stepCounter++)
|
||||
Start-Sleep -Seconds 5
|
||||
#----------------------------------------------------------------------------
|
||||
# Bitlocker Status
|
||||
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
|
||||
$blockerstatus = (Get-BitlockerVolume -MountPoint "C:")
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
Write-ProgressHelper -Message 'Checking For PSC Admin' -StepNumber ($stepCounter++)
|
||||
Start-Sleep -Seconds 5
|
||||
#----------------------------------------------------------------------------
|
||||
# PSC Admin User Check Start
|
||||
|
||||
|
||||
$UserPassword = ConvertTo-SecureString "Restore99!" -AsPlainText -Force
|
||||
$psclocaladmin = $null
|
||||
If ($psclocaladmin = Get-LocalUser pscadmin)
|
||||
{
|
||||
Add-LocalGroupMember -Group "Administrators" -Member "pscadmin"
|
||||
Enable-LocalUser -Name "pscadmin"
|
||||
}
|
||||
Else
|
||||
{
|
||||
# If (!$psclocaladmin)
|
||||
New-LocalUser "pscadmin" -Password $UserPassword -FullName "PSC Admin" -Description "PSC Admin Account" -AccountNeverExpires -PasswordNeverExpires
|
||||
Add-LocalGroupMember -Group "Administrators" -Member "pscadmin"
|
||||
Enable-LocalUser -Name "pscadmin"
|
||||
}
|
||||
|
||||
|
||||
# PSC Admin User Check End
|
||||
#----------------------------------------------------------------------------
|
||||
Write-ProgressHelper -Message 'Creating Restore Point - We Like To Play It Safe!' -StepNumber ($stepCounter++)
|
||||
Start-Sleep -Seconds 10
|
||||
#----------------------------------------------------------------------------
|
||||
# System Restore Check Start
|
||||
|
||||
Enable-ComputerRestore -Drive "C:\"
|
||||
Checkpoint-Computer -Description "New Intune Setup 2019" -RestorePointType MODIFY_SETTINGS
|
||||
|
||||
# System Restore Check End
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
##############################################################################
|
||||
# Computer Sanity Check End
|
||||
##############################################################################
|
||||
Write-ProgressHelper -Message 'Checking For Errors - Its Windows 10, As If There Would Be Errors!?' -StepNumber ($stepCounter++)
|
||||
Start-Sleep -Seconds 5
|
||||
|
||||
# Errors
|
||||
|
||||
If($freespace -lt 32212254720 ) {
|
||||
$freespaceError | Format-Table | Out-File -append "c:\InTune_Log\$env:COMPUTERNAME.log" | Write-Output
|
||||
}
|
||||
else {
|
||||
# No Error To See Here, Keep Moving!
|
||||
}
|
||||
|
||||
|
||||
If ($blockerstatus.protectionstatus -ne "On") {
|
||||
Enable-BitLocker -MountPoint C: -UsedSpaceOnly -SkipHardwareTest -RecoveryKeyPath "c:\InTune_Log\" -RecoveryKeyProtector
|
||||
manage-bde -protectors -get c: >> c:\InTune_Log\$env:Computername-Bitlocker-Recovery-key.txt
|
||||
("BitLocker Was Off") | Format-Table | Out-File -append "c:\InTune_Log\$env:COMPUTERNAME.log" | Write-Output
|
||||
|
||||
}
|
||||
Else
|
||||
{
|
||||
manage-bde -protectors -get c: >> c:\InTune_Log\$env:Computername-Bitlocker-Recovery-key.txt
|
||||
}
|
||||
Start-Sleep -Seconds 1.5
|
||||
if ($BStatus -ne 2)
|
||||
{
|
||||
("$env:username Did Not Plug In To Mains") | Format-Table | Out-File -append "c:\InTune_Log\$env:COMPUTERNAME.log" | Write-Output
|
||||
}
|
||||
|
||||
# AutoPilot Hardware Hash
|
||||
Install-Script -Name Get-WindowsAutoPilotInfo -Force
|
||||
Start-Sleep -Seconds 3
|
||||
Get-WindowsAutoPilotInfo.ps1 -append -OutputFile "c:\InTune_Log\$env:COMPUTERNAME.csv"
|
||||
Start-Sleep -Seconds 2.5
|
||||
|
||||
Stop-Transcript
|
||||
|
||||
# Fail
|
||||
$LogsExist = (Test-Path $InTuneLog)
|
||||
Write-ProgressHelper -Message 'Sending Data To PSC IT' -StepNumber ($stepCounter++)
|
||||
Start-Sleep -Seconds 4
|
||||
if (Test-Path $InTuneLog)
|
||||
{
|
||||
$psclocaladmin | Format-Table | Out-File -append "c:\InTune_Log\$env:COMPUTERNAME.log" | Write-Output
|
||||
("BitLocker Was Off, It has now been switched on by InTune Script. Please try again in an hour") | Format-Table | Out-File -append "c:\InTune_Log\$env:COMPUTERNAME.log" | Write-Output
|
||||
Compress-Archive -Path $InTuneFolder -DestinationPath $InTune_Folder\$env:COMPUTERNAME.zip
|
||||
Start-Sleep -Seconds 5
|
||||
Send-MailMessage -from "$env:username<kurt.frohloff@pscconsulting.com>" -to "IT<it@pscconsulting.com>" -Subject "AAD Intune Upgrade Report Fail $env:computername" -Body "$env:COMPUTERNAME InTune Logs" -Attachments "$InTune_Folder\$env:COMPUTERNAME.zip" -SmtpServer "pscconsulting-com.mail.protection.outlook.com"
|
||||
curl "https://onedrive.live.com/download?cid=77FB0E4F642F10B7&resid=77FB0E4F642F10B7%21273301&authkey=AEReiJb0-g1gGqc" -o "$InTune_Folder\sendfile.ps1"
|
||||
Invoke-Expression (($InTune_Folder)+"\sendfile.ps1")
|
||||
Remove-Item $InTune_Folder\sendfile.ps1 -Force -ErrorAction SilentlyContinue
|
||||
[System.Windows.Forms.MessageBox]::Show("The PSC IT Update Readiness Tool Has Completed Its Task. All Details Have Been Sent To PSC IT.", $Organisation,
|
||||
[System.Windows.Forms.MessageBoxButtons]::OK,
|
||||
[System.Windows.Forms.MessageBoxIcon]::INFORMATION)
|
||||
}
|
||||
Else
|
||||
{
|
||||
("BitLocker Was Already On") | Format-Table | Out-File -append "c:\InTune_Log\$env:COMPUTERNAME.log" | Write-Output
|
||||
$psclocaladmin | Format-Table | Out-File -append "c:\InTune_Log\$env:COMPUTERNAME.log" | Write-Output
|
||||
("$env:COMPUTERNAME has $spacegb GB Free") | Format-Table | Out-File -append "c:\InTune_Log\$env:COMPUTERNAME.log" | Write-Output
|
||||
Compress-Archive -Path $InTuneFolder -DestinationPath $InTune_Folder\$env:COMPUTERNAME.zip
|
||||
Start-Sleep -Seconds 5
|
||||
Send-MailMessage -from "$env:username<kurt.frohloff@pscconsulting.com>" -to "IT<it@pscconsulting.com>" -Subject "AAD Intune Upgrade Report Success $env:computername" -Body "$env:COMPUTERNAME InTune Logs" -Attachments "$InTune_Folder\$env:COMPUTERNAME.zip" -SmtpServer "pscconsulting-com.mail.protection.outlook.com"
|
||||
curl "https://onedrive.live.com/download?cid=77FB0E4F642F10B7&resid=77FB0E4F642F10B7%21273301&authkey=AEReiJb0-g1gGqc" -o "$InTune_Folder\sendfile.ps1"
|
||||
Invoke-Expression (($InTune_Folder)+"\sendfile.ps1")
|
||||
Remove-Item $InTune_Folder\sendfile.ps1 -Force -ErrorAction SilentlyContinue
|
||||
|
||||
[System.Windows.Forms.MessageBox]::Show("The PSC IT Update Readiness Tool Has Completed Its Task. All Details Have Been Sent To PSC IT.", $Organisation,
|
||||
[System.Windows.Forms.MessageBoxButtons]::OK,
|
||||
[System.Windows.Forms.MessageBoxIcon]::INFORMATION)
|
||||
}
|
||||
|
||||
Write-ProgressHelper -Message 'Checkup Complete - Thanks For Playing' -StepNumber ($stepCounter++)
|
||||
Start-Sleep -Seconds 3
|
||||
172
Powershell/From Evernote/NEW_Assign_Teams_AU_or_NZ_DDI.ps1
Normal file
172
Powershell/From Evernote/NEW_Assign_Teams_AU_or_NZ_DDI.ps1
Normal file
@@ -0,0 +1,172 @@
|
||||
$MainMenu = {
|
||||
Write-Host " ************************************************"
|
||||
Write-Host " * Assign Teams Calling Number to AU or NZ User *"
|
||||
Write-Host " ************************************************"
|
||||
Write-Host
|
||||
Write-Host " 1.) Connect To Teams Online"
|
||||
Write-Host " 2.) Export Currently Assigned Numbers"
|
||||
Write-Host " 3.) Assign AU Number"
|
||||
Write-Host " 4.) Assign NZ Number"
|
||||
Write-Host " 5.) Quit"
|
||||
Write-Host
|
||||
Write-Host " Select an option and press Enter: " -nonewline
|
||||
}
|
||||
cls
|
||||
$psc = '@pscconsulting.com'
|
||||
Do {
|
||||
cls
|
||||
Invoke-Command $MainMenu
|
||||
$Select = Read-Host
|
||||
Switch ($Select)
|
||||
{
|
||||
1 {
|
||||
Write-Host "Checking For Teams Module"
|
||||
if (Get-Module -ListAvailable -Name MicrosoftTeams) {
|
||||
Write-Host "MicrosoftTeams Module Already Installed - Importing"
|
||||
Import-Module MicrosoftTeams
|
||||
Connect-MicrosoftTeams
|
||||
}
|
||||
else {
|
||||
Write-Host "MicrosoftTeams Module does not exist - Installing"
|
||||
Install-Module MicrosoftTeams -Force -AllowClobber
|
||||
Import-Module MicrosoftTeams
|
||||
Connect-MicrosoftTeams
|
||||
}
|
||||
}
|
||||
2 {
|
||||
|
||||
function Write-ProgressHelper {
|
||||
param (
|
||||
[int]$StepNumber,
|
||||
[string]$Message
|
||||
)
|
||||
Write-Progress -Activity 'Export All Current DDI Numbers That Are In Use to C:\Temp\' -Status $Message -PercentComplete (($StepNumber / $steps) * 100)
|
||||
}
|
||||
$script:steps = ([System.Management.Automation.PsParser]::Tokenize((gc "$PSScriptRoot\$($MyInvocation.MyCommand.Name)"), [ref]$null) | where { $_.Type -eq 'Command' -and $_.Content -eq 'Write-ProgressHelper' }).Count
|
||||
$stepCounter = 0
|
||||
Write-ProgressHelper -Message 'Checking For Temp Direcory' -StepNumber ($stepCounter++)
|
||||
Start-Sleep -Seconds 2.5
|
||||
$ErrorActionPreference="SilentlyContinue"
|
||||
#Check If Directory Exists #############
|
||||
$DirectoryToCreate = "C:\Temp\"
|
||||
if (-not (Test-Path -LiteralPath $DirectoryToCreate)) {
|
||||
Write-Host "Directory does not exist - creating..."
|
||||
New-Item -Path $DirectoryToCreate -ItemType Directory -ErrorAction Stop | Out-Null #-Force
|
||||
Write-Host "Successfully created directory '$DirectoryToCreate'."
|
||||
}
|
||||
else {
|
||||
Write-Host "Directory already exists"
|
||||
}
|
||||
Write-ProgressHelper -Message 'Checking For Temp Direcory' -StepNumber ($stepCounter++)
|
||||
Start-Sleep -Seconds 2.5
|
||||
#Connect to Teams
|
||||
Write-Host "Connecting to MS Teams"
|
||||
Connect-MicrosoftTeams
|
||||
Write-ProgressHelper -Message 'Getting Used Numbers and Exporting to CSV' -StepNumber ($stepCounter++)
|
||||
Start-Sleep -Seconds 2.5
|
||||
#Settings ##############################
|
||||
#. "_Settings.ps1" | Out-Null
|
||||
$FileName = "TeamsAssignedNumbers_" + (Get-Date -Format s).replace(":","-") +".csv"
|
||||
$FilePath = "C:\Temp\$FileName"
|
||||
$OutputType = "CSV" #OPTIONS: CSV - Outputs CSV to specified FilePath, CONSOLE - Outputs to console
|
||||
##############################
|
||||
$Regex1 = '^(?:tel:)?(?:\+)?(\d+)(?:;ext=(\d+))?(?:;([\w-]+))?$'
|
||||
$Array1 = @()
|
||||
#Get Users with LineURI
|
||||
$UsersLineURI = Get-CsOnlineUser -Filter {LineURI -ne $Null}
|
||||
if($UsersLineURI -ne $null)
|
||||
{
|
||||
foreach($item in $UsersLineURI)
|
||||
{
|
||||
$Matches = @()
|
||||
$Item.LineURI -match $Regex1 | out-null
|
||||
|
||||
$myObject1 = New-Object System.Object
|
||||
$myObject1 | Add-Member -type NoteProperty -name "LineURI" -Value $Item.LineURI
|
||||
$myObject1 | Add-Member -type NoteProperty -name "DDI" -Value $Matches[1]
|
||||
# $myObject1 | Add-Member -type NoteProperty -name "Ext" -Value $Matches[2]
|
||||
$myObject1 | Add-Member -type NoteProperty -name "DisplayName" -Value $Item.DisplayName
|
||||
# $myObject1 | Add-Member -type NoteProperty -name "FirstName" -Value $Item.FirstName
|
||||
# $myObject1 | Add-Member -type NoteProperty -name "LastName" -Value $Item.LastName
|
||||
$myObject1 | Add-Member -type NoteProperty -name "Type" -Value "User"
|
||||
$Array1 += $myObject1
|
||||
}
|
||||
}
|
||||
#Get meeting room numbers
|
||||
$MeetingRoomLineURI = Get-CsMeetingRoom -Filter {LineURI -ne $Null}
|
||||
if($MeetingRoomLineURI -ne $null)
|
||||
{
|
||||
Write-Verbose "Processing Meeting Room Numbers"
|
||||
foreach($Item in $MeetingRoomLineURI)
|
||||
{
|
||||
$Matches = @()
|
||||
$Item.LineURI -match $Regex1 | out-null
|
||||
|
||||
$myObject1 = New-Object System.Object
|
||||
$myObject1 | Add-Member -type NoteProperty -name "LineURI" -Value $Item.LineURI
|
||||
$myObject1 | Add-Member -type NoteProperty -name "DDI" -Value $Matches[1]
|
||||
$myObject1 | Add-Member -type NoteProperty -name "Ext" -Value $Matches[2]
|
||||
$myObject1 | Add-Member -type NoteProperty -name "DisplayName" -Value $Item.DisplayName
|
||||
$myObject1 | Add-Member -type NoteProperty -name "Type" -Value "MeetingRoom"
|
||||
$Array1 += $myObject1
|
||||
}
|
||||
}
|
||||
#Get online resource accounts
|
||||
$OnlineApplicationInstanceLineURI = Get-CsOnlineApplicationInstance | where {$_.PhoneNumber -ne $Null}
|
||||
if($OnlineApplicationInstanceLineURI -ne $null)
|
||||
{
|
||||
Write-Verbose "Processing Online Application Instances (Resource Accounts) Numbers"
|
||||
foreach($Item in $OnlineApplicationInstanceLineURI)
|
||||
{
|
||||
$Matches = @()
|
||||
$Item.PhoneNumber -match $Regex1 | out-null
|
||||
|
||||
$myObject1 = New-Object System.Object
|
||||
$myObject1 | Add-Member -type NoteProperty -name "LineURI" -Value $Item.PhoneNumber
|
||||
$myObject1 | Add-Member -type NoteProperty -name "DDI" -Value $Matches[1]
|
||||
$myObject1 | Add-Member -type NoteProperty -name "Ext" -Value $Matches[2]
|
||||
$myObject1 | Add-Member -type NoteProperty -name "DisplayName" -Value $Item.DisplayName
|
||||
$myObject1 | Add-Member -type NoteProperty -name "Type" -Value $(if ($item.ApplicationId -eq "ce933385-9390-45d1-9512-c8d228074e07") {"Auto Attendant Resource Account"} elseif ($item.ApplicationId -eq "11cd3e2e-fccb-42ad-ad00-878b93575e07") {"Call Queue Resource Account"} else {"Unknown Resource Account"})
|
||||
$Array1 += $myObject1
|
||||
}
|
||||
}
|
||||
if($OutputType -eq "CSV")
|
||||
{
|
||||
$Array1 | export-csv $FilePath -NoTypeInformation
|
||||
Write-Host "ALL DONE!! Your file has been saved to $FilePath."
|
||||
}
|
||||
elseif($OutputType -eq "CONSOLE")
|
||||
{
|
||||
$Array1 | FT -AutoSize -Property LineURI,DDI,Ext,DisplayName,Type
|
||||
Write-Host "ALL DONE!!"
|
||||
}
|
||||
else
|
||||
{
|
||||
$Array1 | FT -AutoSize -Property LineURI,DDI,Ext,DisplayName,Type
|
||||
Write-Host "WARNING: Valid output type not set, defaulted to console."
|
||||
Read-Host -Prompt "Press any key to continue..."
|
||||
}
|
||||
}
|
||||
3 {
|
||||
$firstname = Read-Host -Prompt "Enter User First Name"
|
||||
$lastname = Read-Host -Prompt "Enter User Last Name"
|
||||
$AUPhone = Read-Host -Prompt "Enter User Phone Number, Including Single Digit Area Code Only. Country Code Not Required"
|
||||
$Name = "$firstname.$lastname@pscconsulting.com"
|
||||
Set-CsPhoneNumberAssignment -Identity $Name -PhoneNumber +61$AUPhone -PhoneNumberType DirectRouting
|
||||
Set-CsPhoneNumberAssignment -Identity $Name -EnterpriseVoiceEnabled $true
|
||||
Grant-CsOnlineVoiceRoutingPolicy -Identity $Name -PolicyName MacTelAustralia
|
||||
Read-Host -Prompt "Press any key to continue..."
|
||||
}
|
||||
4 {
|
||||
$firstname = Read-Host -Prompt "Enter User First Name"
|
||||
$lastname = Read-Host -Prompt "Enter User Last Name"
|
||||
$NZPhone = Read-Host -Prompt "Enter User Phone Number, Including Single Digit Area Code Only. Country Code Not Required"
|
||||
$Name = "$firstname.$lastname@pscconsulting.com"
|
||||
Set-CsPhoneNumberAssignment -Identity $Name -PhoneNumber +64$NZPhone -PhoneNumberType DirectRouting
|
||||
Set-CsPhoneNumberAssignment -Identity $Name -EnterpriseVoiceEnabled $true
|
||||
Grant-CsOnlineVoiceRoutingPolicy -Identity $Name -PolicyName "Vocus NZ International"
|
||||
Read-Host -Prompt "Press any key to continue..."
|
||||
}
|
||||
}
|
||||
}
|
||||
While ($Select -ne 5)
|
||||
@@ -0,0 +1,28 @@
|
||||
@echo off
|
||||
:: BatchGotAdmin
|
||||
::-------------------------------------
|
||||
REM --> Check for permissions
|
||||
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
|
||||
|
||||
REM --> If error flag set, we do not have admin.
|
||||
if '%errorlevel%' NEQ '0' (
|
||||
echo Requesting administrative privileges...
|
||||
goto UACPrompt
|
||||
) else ( goto gotAdmin )
|
||||
|
||||
:UACPrompt
|
||||
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
|
||||
set params = %*:"="
|
||||
echo UAC.ShellExecute "cmd.exe", "/c %~s0 %params%", "", "runas", 1 >> "%temp%\getadmin.vbs"
|
||||
|
||||
"%temp%\getadmin.vbs"
|
||||
del "%temp%\getadmin.vbs"
|
||||
exit /B
|
||||
|
||||
:gotAdmin
|
||||
pushd "%CD%"
|
||||
CD /D "%~dp0"
|
||||
::--------------------------------------
|
||||
|
||||
powershell -command "& {Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force}"
|
||||
powershell ./Intune.ps1
|
||||
Binary file not shown.
588
Powershell/From Evernote/Robocopy with file exclude.html
Normal file
588
Powershell/From Evernote/Robocopy with file exclude.html
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,11 @@
|
||||
#Setting registry key to block AAD Registration to 3rd party tenants.
|
||||
$RegistryLocation = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WorkplaceJoin\"
|
||||
$keyname = "BlockAADWorkplaceJoin"
|
||||
#Test if path exists and create if missing
|
||||
if (!(Test-Path -Path $RegistryLocation)){
|
||||
Write-Output "Registry location missing. Creating"
|
||||
New-Item $RegistryLocation | Out-Null
|
||||
}
|
||||
#Force create key with value 1
|
||||
New-ItemProperty -Path $RegistryLocation -Name $keyname -PropertyType DWord -Value 1 -Force | Out-Null
|
||||
Write-Output "Registry key set"
|
||||
@@ -0,0 +1,54 @@
|
||||
<#
|
||||
.Synopsis Detects, downloads, installs and configures the latest version of TeamViewer.
|
||||
.Notes
|
||||
Requires TeamViewer 14.
|
||||
|
||||
TeamViewer Installation Documentation
|
||||
https://community.teamviewer.com/t5/Knowledge-Base/Mass-deployment-improvements/ta-p/39639
|
||||
#>
|
||||
$ConfigurationID = "64uyck9"
|
||||
$ApiToken = "6615740-y9LI6bdNq5QtaDtiGVTN"
|
||||
$ComputerName = $ENV:COMPUTERNAME
|
||||
|
||||
if (Test-Path 'C:\Program Files (x86)\TeamViewer\TeamViewer.exe') {
|
||||
Write-Host 'Team Viewer already installed.'
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host 'Installing TeamViewer.'
|
||||
|
||||
Write-Host 'Downloading TeamViewer Host Setup.'
|
||||
$SetupFilePath = Join-Path $ENV:TEMP "TeamViewer_Host_Setup-idc$($ConfigurationID).exe"
|
||||
|
||||
$response = Invoke-RestMethod "https://get.teamviewer.com/$ConfigurationID"
|
||||
$json = '{}'
|
||||
if ($response -match 'configId = "(?<ConfigId>[^"]+).*\n.*version = "(?<Version>[^"]+).*\n.*isCustomModule = (?<IsCustomModule>[^"]+);.*\n.*subdomain = "(?<Subdomain>[^"]+)(?<ConnectionId>)' ) {
|
||||
$Matches.Remove(0)
|
||||
$Matches['IsCustomModule'] = if ($Matches['IsCustomModule'] -eq 'true') { $true } else { $false }
|
||||
$json = [PsCustomObject]$Matches | ConvertTo-Json
|
||||
}
|
||||
else {
|
||||
throw 'Expected JSON values not found in initial HTML page'
|
||||
}
|
||||
|
||||
$DownloadUri = Invoke-RestMethod -Uri 'https://get.teamviewer.com/api/CustomDesign' -Method Post -Body $json -ContentType 'application/json'
|
||||
Invoke-WebRequest -Uri $DownloadUri -OutFile $SetupFilePath
|
||||
|
||||
|
||||
if (-not (Test-Path $SetupFilePath)) {
|
||||
throw 'TeamViewer_Setup.exe failed to download.'
|
||||
}
|
||||
|
||||
Write-Host 'Installing.'
|
||||
& $SetupFilePath /S | Write-Output
|
||||
Write-Debug "$SetupFilePath LastExitCode = $LASTEXITCODE"
|
||||
|
||||
Write-Host 'Configuring'
|
||||
& "C:\Program Files (x86)\TeamViewer\TeamViewer.exe" assign --api-token $ApiToken --grant-easy-access --reassign --alias $ComputerName | Write-Output
|
||||
Write-Debug "TeamViewer.exe assign LastExitCode = $LASTEXITCODE"
|
||||
|
||||
Write-Host 'Cleaning up.'
|
||||
$SetupTempFolder = Join-Path $ENV:TEMP 'TeamViewer'
|
||||
$SetupFilePath, $SetupTempFolder | Remove-Item -Recurse
|
||||
|
||||
Write-Host 'Complete.'
|
||||
@@ -0,0 +1,51 @@
|
||||
param([switch]$Elevated)
|
||||
function Check-Admin {
|
||||
$currentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())
|
||||
$currentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
|
||||
}
|
||||
if ((Check-Admin) -eq $false) {
|
||||
if ($elevated)
|
||||
{
|
||||
# could not elevate, quit
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
Start-Process powershell.exe -Verb RunAs -ArgumentList ('-noprofile -noexit -file "{0}" -elevated' -f ($myinvocation.MyCommand.Definition))
|
||||
}
|
||||
exit
|
||||
}
|
||||
$TempInstallDir = "c:\teamviewer_install\"
|
||||
if (Test-Path $TempInstallDir) {
|
||||
Remove-Item $TempInstallDir -Recurse -Force
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "Install Start"
|
||||
}
|
||||
$TeamViewerFileName = "C:\Program Files (x86)\TeamViewer\TeamViewer.exe"
|
||||
$TeamViewer64FileName = "C:\Program Files\TeamViewer\TeamViewer.exe"
|
||||
|
||||
|
||||
function not-exist { -not (Test-Path -Path $TeamViewer64FileName) }
|
||||
function not-exist { -not (Test-Path -Path $TeamViewerFileName) }
|
||||
if (-not (Test-Path -Path $TeamViewerFileName)) {}
|
||||
if (-not (Test-Path -Path $TeamViewer64FileName)) {
|
||||
mkdir c:\teamviewer_install
|
||||
$url = "https://download.teamviewer.com/download/version_15x/TeamViewer_MSI32.zip"
|
||||
$output = "c:\teamviewer_install\TeamviewerHost.zip"
|
||||
$tvdir = "c:\teamviewer_install"
|
||||
$start_time = Get-Date
|
||||
|
||||
$wc = New-Object System.Net.WebClient
|
||||
$wc.DownloadFile($url, $output)
|
||||
Write-Host "Teamviewer Downloaded"
|
||||
sleep 3
|
||||
Expand-Archive -LiteralPath $output -DestinationPath $tvdir -Force
|
||||
msiexec.exe /i "c:\teamviewer_install\Host\Teamviewer_Host.msi" /qn CUSTOMCONFIGID=6988pev APITOKEN=6581446-B1aEz7nIk9k92p4G7C1R ASSIGNMENTOPTIONS="--grant-easy-access"
|
||||
Write-Host "Teamviewer Installed"
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Host "TeamViewer Already Installed"
|
||||
}
|
||||
40
Powershell/From Evernote/Uninstall-IntuneClient.ps1
Normal file
40
Powershell/From Evernote/Uninstall-IntuneClient.ps1
Normal file
@@ -0,0 +1,40 @@
|
||||
function Get-ServiceId {
|
||||
#Set the registry path containing the service ID
|
||||
$RegistryPath = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\OnlineManagement"
|
||||
try {
|
||||
#Get all the names of the items in the registry location
|
||||
$RegistryItems = (Get-ChildItem -Path Registry::$RegistryPath -ErrorAction Stop).Name
|
||||
#Loop through all the results
|
||||
foreach ($RegistryItem in $RegistryItems) {
|
||||
#Find the result that starts with the registry location followed by the first sign of a GUID
|
||||
if ($RegistryItem.StartsWith("$RegistryPath\{")) {
|
||||
#Replace the registry location with nothing to get the GUID
|
||||
$ServiceId = $RegistryItem.Replace("$RegistryPath\","")
|
||||
break
|
||||
}
|
||||
}
|
||||
return $ServiceId
|
||||
}
|
||||
catch {
|
||||
Write-Output "The Microsoft Intune client is not installed"
|
||||
}
|
||||
}
|
||||
|
||||
function Start-Uninstall {
|
||||
param (
|
||||
[parameter(Mandatory=$true)]$ServiceId
|
||||
)
|
||||
try {
|
||||
#Set the ProvisioningUtil location and parameters
|
||||
$ProvisioningUtilPath = "C:\Program Files\Microsoft\OnlineManagement\Common"
|
||||
$ProvisioningUtilExecutable = "ProvisioningUtil.exe"
|
||||
$ProvisioningUtilArguments = "/UninstallClient /ServiceId $ServiceId /TaskName 'tempTask' /SubEventId 16"
|
||||
#Trigger the uninstall of the Microsoft Intune client
|
||||
Start-Process -FilePath "$($ProvisioningUtilPath)\$($ProvisioningUtilExecutable)" -ArgumentList $ProvisioningUtilArguments -Wait -PassThru
|
||||
}
|
||||
catch {
|
||||
Write-Output "Failed to trigger the uninstall of the Microsoft Intune client"
|
||||
}
|
||||
}
|
||||
|
||||
Start-Uninstall (Get-ServiceId)
|
||||
545
Powershell/Invoke-DiskCleanupScan.ps1
Normal file
545
Powershell/Invoke-DiskCleanupScan.ps1
Normal file
@@ -0,0 +1,545 @@
|
||||
#Requires -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Full C: drive space recovery scanner with user confirmation before cleanup.
|
||||
|
||||
.DESCRIPTION
|
||||
Scans for recoverable disk space across common Windows Server bloat sources.
|
||||
Reports findings with sizes, then prompts for confirmation before touching anything.
|
||||
|
||||
.NOTES
|
||||
Supports: Windows Server 2016, 2019, 2022, 2025
|
||||
Run as: Administrator
|
||||
Author: SBCIT
|
||||
#>
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'SilentlyContinue'
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# HELPERS
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
function Format-Size {
|
||||
param([long]$Bytes)
|
||||
if ($Bytes -ge 1GB) { return "{0:N2} GB" -f ($Bytes / 1GB) }
|
||||
if ($Bytes -ge 1MB) { return "{0:N2} MB" -f ($Bytes / 1MB) }
|
||||
if ($Bytes -ge 1KB) { return "{0:N2} KB" -f ($Bytes / 1KB) }
|
||||
return "$Bytes B"
|
||||
}
|
||||
|
||||
function Get-FolderSize {
|
||||
param([string]$Path)
|
||||
if (-not (Test-Path $Path)) { return 0 }
|
||||
try {
|
||||
(Get-ChildItem -Path $Path -Recurse -Force -File -ErrorAction SilentlyContinue |
|
||||
Measure-Object -Property Length -Sum).Sum
|
||||
} catch { 0 }
|
||||
}
|
||||
|
||||
function Get-RecycleBinSize {
|
||||
$total = 0
|
||||
try {
|
||||
$shell = New-Object -ComObject Shell.Application
|
||||
$recycle = $shell.Namespace(0xA)
|
||||
foreach ($item in $recycle.Items()) {
|
||||
try { $total += $item.Size } catch {}
|
||||
}
|
||||
} catch {}
|
||||
return $total
|
||||
}
|
||||
|
||||
function Write-Header {
|
||||
param([string]$Text)
|
||||
Write-Host "`n [$Text]" -ForegroundColor Cyan
|
||||
Write-Host " $('─' * 60)" -ForegroundColor DarkGray
|
||||
}
|
||||
|
||||
function Write-FindingLine {
|
||||
param([string]$Label, [long]$Bytes, [string]$Note = '')
|
||||
$size = Format-Size $Bytes
|
||||
$color = if ($Bytes -gt 500MB) { 'Yellow' } elseif ($Bytes -gt 50MB) { 'White' } else { 'DarkGray' }
|
||||
$noteStr = if ($Note) { " ($Note)" } else { '' }
|
||||
Write-Host (" {0,-48} {1,10}{2}" -f $Label, $size, $noteStr) -ForegroundColor $color
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# BANNER
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
Clear-Host
|
||||
Write-Host ""
|
||||
Write-Host " ╔══════════════════════════════════════════════════════════╗" -ForegroundColor DarkCyan
|
||||
Write-Host " ║ SBCIT // C: DRIVE CLEANUP SCANNER ║" -ForegroundColor DarkCyan
|
||||
Write-Host " ║ Windows Server 2016 → Current ║" -ForegroundColor DarkCyan
|
||||
Write-Host " ╚══════════════════════════════════════════════════════════╝" -ForegroundColor DarkCyan
|
||||
Write-Host ""
|
||||
Write-Host " Host : $($env:COMPUTERNAME)" -ForegroundColor Gray
|
||||
Write-Host " User : $($env:USERNAME)" -ForegroundColor Gray
|
||||
Write-Host " Date : $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# PRE-SCAN: DRIVE STATE
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
$drive = Get-PSDrive C
|
||||
$freeGB = [math]::Round($drive.Free / 1GB, 2)
|
||||
$totalGB = [math]::Round(($drive.Used + $drive.Free) / 1GB, 2)
|
||||
$usedGB = [math]::Round($drive.Used / 1GB, 2)
|
||||
$freePct = [math]::Round(($drive.Free / ($drive.Used + $drive.Free)) * 100, 1)
|
||||
|
||||
Write-Host " C: Drive Status" -ForegroundColor White
|
||||
Write-Host " $('─' * 60)" -ForegroundColor DarkGray
|
||||
Write-Host (" Total: {0} GB Used: {1} GB Free: {2} GB ({3}% free)" -f $totalGB, $usedGB, $freeGB, $freePct) -ForegroundColor $(if ($freePct -lt 15) { 'Red' } elseif ($freePct -lt 25) { 'Yellow' } else { 'Green' })
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# SCAN TARGETS — build a list of items
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
Write-Host "`n Scanning... this may take a moment.`n" -ForegroundColor DarkYellow
|
||||
|
||||
$scanResults = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
|
||||
function Add-Result {
|
||||
param(
|
||||
[string]$Category,
|
||||
[string]$Label,
|
||||
[string]$Path,
|
||||
[long]$Size,
|
||||
[string]$CleanupType, # Folder | RecycleBin | WindowsCleanMgr | EventLogs | TempFiles | IISLogs | WER | DeliveryOpt | MiniDumps | PrefetchCache
|
||||
[string]$Note = ''
|
||||
)
|
||||
if ($Size -gt 0) {
|
||||
$scanResults.Add([PSCustomObject]@{
|
||||
Category = $Category
|
||||
Label = $Label
|
||||
Path = $Path
|
||||
Size = $Size
|
||||
CleanupType = $CleanupType
|
||||
Note = $Note
|
||||
Selected = $true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
# ── TEMP FILES ──────────────────────────────
|
||||
$winTemp = Get-FolderSize "C:\Windows\Temp"
|
||||
$sysTemp = Get-FolderSize $env:TEMP
|
||||
$userTemp = Get-FolderSize "C:\Users\$env:USERNAME\AppData\Local\Temp"
|
||||
|
||||
Add-Result "Temp Files" "Windows Temp (C:\Windows\Temp)" "C:\Windows\Temp" $winTemp "Folder"
|
||||
Add-Result "Temp Files" "System Temp ($env:TEMP)" $env:TEMP $sysTemp "Folder"
|
||||
Add-Result "Temp Files" "User Temp (AppData\Local\Temp)" "C:\Users\$env:USERNAME\AppData\Local\Temp" $userTemp "Folder"
|
||||
|
||||
# ── WINDOWS UPDATE / WINSXS ─────────────────
|
||||
$softwaredist = Get-FolderSize "C:\Windows\SoftwareDistribution\Download"
|
||||
$winsxsBackup = Get-FolderSize "C:\Windows\WinSxS\Backup"
|
||||
|
||||
Add-Result "Windows Update" "SoftwareDistribution\Download" "C:\Windows\SoftwareDistribution\Download" $softwaredist "Folder" "Cached WU downloads"
|
||||
Add-Result "Windows Update" "WinSxS\Backup" "C:\Windows\WinSxS\Backup" $winsxsBackup "Folder" "Old component backups"
|
||||
|
||||
# ── CBS / COMPONENT LOGS ────────────────────
|
||||
$cbsLogs = Get-FolderSize "C:\Windows\Logs\CBS"
|
||||
Add-Result "System Logs" "CBS Logs (C:\Windows\Logs\CBS)" "C:\Windows\Logs\CBS" $cbsLogs "Folder"
|
||||
|
||||
# ── WINDOWS ERROR REPORTING ──────────────────
|
||||
$werUser = Get-FolderSize "C:\ProgramData\Microsoft\Windows\WER\ReportQueue"
|
||||
$werArch = Get-FolderSize "C:\ProgramData\Microsoft\Windows\WER\ReportArchive"
|
||||
$werUser2 = Get-FolderSize "C:\Users\$env:USERNAME\AppData\Local\Microsoft\Windows\WER"
|
||||
|
||||
Add-Result "Error Reporting" "WER ReportQueue" "C:\ProgramData\Microsoft\Windows\WER\ReportQueue" $werUser "WER"
|
||||
Add-Result "Error Reporting" "WER ReportArchive" "C:\ProgramData\Microsoft\Windows\WER\ReportArchive" $werArch "WER"
|
||||
Add-Result "Error Reporting" "WER User Reports" "C:\Users\$env:USERNAME\AppData\Local\Microsoft\Windows\WER" $werUser2 "WER"
|
||||
|
||||
# ── MINIDUMPS ───────────────────────────────
|
||||
$miniDump = Get-FolderSize "C:\Windows\Minidump"
|
||||
$memDump = if (Test-Path "C:\Windows\MEMORY.DMP") { (Get-Item "C:\Windows\MEMORY.DMP").Length } else { 0 }
|
||||
|
||||
Add-Result "Crash Dumps" "Minidumps (C:\Windows\Minidump)" "C:\Windows\Minidump" $miniDump "MiniDumps"
|
||||
Add-Result "Crash Dumps" "Full Memory Dump (MEMORY.DMP)" "C:\Windows\MEMORY.DMP" $memDump "Folder" "Single file"
|
||||
|
||||
# ── PREFETCH ────────────────────────────────
|
||||
$prefetch = Get-FolderSize "C:\Windows\Prefetch"
|
||||
Add-Result "Prefetch" "Prefetch Cache" "C:\Windows\Prefetch" $prefetch "PrefetchCache" "Server may have Prefetch disabled"
|
||||
|
||||
# ── DELIVERY OPTIMISATION ───────────────────
|
||||
$delivOptFiles = Get-FolderSize "C:\Windows\SoftwareDistribution\DeliveryOptimization"
|
||||
$delivOpt2 = Get-FolderSize "C:\Windows\ServiceProfiles\NetworkService\AppData\Local\Microsoft\Windows\DeliveryOptimization"
|
||||
|
||||
Add-Result "Delivery Optim." "DeliveryOptimization Cache" "C:\Windows\SoftwareDistribution\DeliveryOptimization" $delivOptFiles "DeliveryOpt"
|
||||
Add-Result "Delivery Optim." "DeliveryOptimization (NetworkSvc)" "C:\Windows\ServiceProfiles\NetworkService\AppData\Local\Microsoft\Windows\DeliveryOptimization" $delivOpt2 "DeliveryOpt"
|
||||
|
||||
# ── IIS LOGS ────────────────────────────────
|
||||
$iisLogPaths = @(
|
||||
"C:\inetpub\logs\LogFiles",
|
||||
"C:\Windows\System32\LogFiles\W3SVC1"
|
||||
)
|
||||
foreach ($iisPath in $iisLogPaths) {
|
||||
$sz = Get-FolderSize $iisPath
|
||||
Add-Result "IIS Logs" "IIS Logs ($iisPath)" $iisPath $sz "IISLogs" "Files >30 days"
|
||||
}
|
||||
|
||||
# ── WINDOWS EVENT LOGS ──────────────────────
|
||||
$evtxSize = 0
|
||||
try {
|
||||
$evtxSize = (Get-ChildItem "C:\Windows\System32\winevt\Logs" -Filter "*.evtx" -File -ErrorAction SilentlyContinue |
|
||||
Measure-Object -Property Length -Sum).Sum
|
||||
} catch {}
|
||||
Add-Result "Event Logs" "Windows Event Logs (*.evtx)" "C:\Windows\System32\winevt\Logs" $evtxSize "EventLogs" "Will clear all logs — review first"
|
||||
|
||||
# ── RECYCLE BIN ─────────────────────────────
|
||||
$rbSize = Get-RecycleBinSize
|
||||
Add-Result "Recycle Bin" "C: Recycle Bin" "C:\`$Recycle.Bin" $rbSize "RecycleBin"
|
||||
|
||||
# ── THUMBNAIL CACHE ──────────────────────────
|
||||
$thumbCache = Get-FolderSize "C:\Users\$env:USERNAME\AppData\Local\Microsoft\Windows\Explorer"
|
||||
Add-Result "Cache" "Thumbnail Cache" "C:\Users\$env:USERNAME\AppData\Local\Microsoft\Windows\Explorer" $thumbCache "Folder"
|
||||
|
||||
# ── WINDOWS INSTALLER PATCH CACHE ───────────
|
||||
$installerCache = Get-FolderSize "C:\Windows\Installer\`$PatchCache`$"
|
||||
Add-Result "Installer Cache" "MSI Patch Cache" "C:\Windows\Installer\`$PatchCache`$" $installerCache "Folder" "Caution: may affect MSI repair"
|
||||
|
||||
# ── FONT CACHE ──────────────────────────────
|
||||
$fontCache = Get-FolderSize "C:\Windows\ServiceProfiles\LocalService\AppData\Local\FontCache"
|
||||
Add-Result "Cache" "Font Cache" "C:\Windows\ServiceProfiles\LocalService\AppData\Local\FontCache" $fontCache "Folder" "Rebuilds automatically"
|
||||
|
||||
# ── OLD USER PROFILES (non-system) ──────────
|
||||
$systemProfiles = @('Administrator','Default','Default User','Public','All Users','LocalService','NetworkService','systemprofile')
|
||||
$oldProfiles = Get-ChildItem "C:\Users" -Directory -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.Name -notin $systemProfiles -and $_.Name -ne $env:USERNAME }
|
||||
|
||||
foreach ($prof in $oldProfiles) {
|
||||
$sz = Get-FolderSize $prof.FullName
|
||||
Add-Result "User Profiles" "Old Profile: $($prof.Name)" $prof.FullName $sz "Folder" "Manual verification recommended"
|
||||
}
|
||||
|
||||
# ── DOWNLOADED PROGRAM FILES ────────────────
|
||||
$dpf = Get-FolderSize "C:\Windows\Downloaded Program Files"
|
||||
Add-Result "Legacy" "Downloaded Program Files" "C:\Windows\Downloaded Program Files" $dpf "Folder"
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# DISPLAY FINDINGS
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
if ($scanResults.Count -eq 0) {
|
||||
Write-Host "`n Nothing significant found. Drive is already clean." -ForegroundColor Green
|
||||
exit 0
|
||||
}
|
||||
|
||||
$totalRecoverable = ($scanResults | Measure-Object -Property Size -Sum).Sum
|
||||
|
||||
Write-Host ""
|
||||
Write-Host " ╔══════════════════════════════════════════════════════════╗" -ForegroundColor DarkCyan
|
||||
Write-Host " ║ SCAN RESULTS ║" -ForegroundColor DarkCyan
|
||||
Write-Host " ╚══════════════════════════════════════════════════════════╝" -ForegroundColor DarkCyan
|
||||
|
||||
# Group by category
|
||||
$grouped = $scanResults | Group-Object Category
|
||||
foreach ($group in ($grouped | Sort-Object Name)) {
|
||||
Write-Header $group.Name
|
||||
foreach ($item in ($group.Group | Sort-Object Size -Descending)) {
|
||||
Write-FindingLine -Label $item.Label -Bytes $item.Size -Note $item.Note
|
||||
}
|
||||
}
|
||||
|
||||
$catSize = ($scanResults | Measure-Object -Property Size -Sum).Sum
|
||||
Write-Host ""
|
||||
Write-Host (" {0,-48} {1,10}" -f "TOTAL RECOVERABLE", (Format-Size $catSize)) -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# SELECTIVE CONFIRMATION
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
Write-Host " ╔══════════════════════════════════════════════════════════╗" -ForegroundColor DarkYellow
|
||||
Write-Host " ║ CLEANUP OPTIONS ║" -ForegroundColor DarkYellow
|
||||
Write-Host " ╚══════════════════════════════════════════════════════════╝" -ForegroundColor DarkYellow
|
||||
Write-Host ""
|
||||
Write-Host " Options:" -ForegroundColor White
|
||||
Write-Host " [A] Clean ALL items listed above" -ForegroundColor White
|
||||
Write-Host " [S] Select items individually" -ForegroundColor White
|
||||
Write-Host " [X] Exit — do nothing" -ForegroundColor White
|
||||
Write-Host ""
|
||||
|
||||
$choice = Read-Host " Your choice"
|
||||
|
||||
switch ($choice.Trim().ToUpper()) {
|
||||
|
||||
'X' {
|
||||
Write-Host "`n Nothing touched. Smart move — always look before you cut." -ForegroundColor DarkGray
|
||||
exit 0
|
||||
}
|
||||
|
||||
'S' {
|
||||
Write-Host ""
|
||||
$idx = 0
|
||||
foreach ($item in $scanResults) {
|
||||
$idx++
|
||||
$prompt = " [$idx] Clean '{0}' ({1})? [Y/N]" -f $item.Label, (Format-Size $item.Size)
|
||||
$ans = Read-Host $prompt
|
||||
$item.Selected = ($ans.Trim().ToUpper() -eq 'Y')
|
||||
}
|
||||
$selected = $scanResults | Where-Object { $_.Selected }
|
||||
if (-not $selected) {
|
||||
Write-Host "`n Nothing selected. Exiting." -ForegroundColor DarkGray
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
|
||||
'A' {
|
||||
$selected = $scanResults
|
||||
$confirm = Read-Host "`n Confirm clean ALL $(Format-Size $totalRecoverable) of data? [YES to proceed]"
|
||||
if ($confirm.Trim().ToUpper() -ne 'YES') {
|
||||
Write-Host "`n Aborted." -ForegroundColor DarkGray
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
|
||||
default {
|
||||
Write-Host "`n Invalid choice. Exiting." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# CLEANUP EXECUTION
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
Write-Host ""
|
||||
Write-Host " ╔══════════════════════════════════════════════════════════╗" -ForegroundColor DarkRed
|
||||
Write-Host " ║ EXECUTING CLEANUP ║" -ForegroundColor DarkRed
|
||||
Write-Host " ╚══════════════════════════════════════════════════════════╝" -ForegroundColor DarkRed
|
||||
Write-Host ""
|
||||
|
||||
$freed = 0
|
||||
|
||||
foreach ($item in $selected) {
|
||||
Write-Host " → $($item.Label)..." -ForegroundColor DarkYellow -NoNewline
|
||||
|
||||
try {
|
||||
switch ($item.CleanupType) {
|
||||
|
||||
'Folder' {
|
||||
if (Test-Path $item.Path) {
|
||||
Get-ChildItem -Path $item.Path -Recurse -Force -ErrorAction SilentlyContinue |
|
||||
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
|
||||
$freed += $item.Size
|
||||
Write-Host " done." -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " path not found, skipped." -ForegroundColor DarkGray
|
||||
}
|
||||
}
|
||||
|
||||
'RecycleBin' {
|
||||
Clear-RecycleBin -Force -ErrorAction SilentlyContinue
|
||||
$freed += $item.Size
|
||||
Write-Host " done." -ForegroundColor Green
|
||||
}
|
||||
|
||||
'EventLogs' {
|
||||
# ── STEP 1: Export all non-empty logs to .evtx ──────────────
|
||||
Write-Host ""
|
||||
Write-Host " Backing up event logs before wipe..." -ForegroundColor DarkYellow
|
||||
|
||||
$timestamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||
$exportRoot = Join-Path $env:TEMP "EventLogBackup_$timestamp"
|
||||
$zipPath = Join-Path $env:TEMP "$($env:COMPUTERNAME)_EventLogs_$timestamp.zip"
|
||||
$uploadUrl = 'https://pebkac.pro/api/upload'
|
||||
$uploadToken = 'MTc3Njg5NzIxOTk0NQ==.NGYyMDY1Y2I0NDNjYTk0NTlhZDgwNTRlLmE3NWZkNjcwMDljODQwM2Y3MzhkZjA4NDFhY2I1NWYwODZhMTdmZjdiZjZjYjMwNjFiNzM5ZGRkM2ZiZWIzZGM1Yjg0OTA4Njk3ZTcyYTQ5MDdlMWYzMzQ5MDdlOTNhNWI5ZDdhZDc1OWVlOTljZWQ3MmU1ZjliODgyYjNkYTBhOGQuZWJkZGE4YmIyOWMxMWU2MGNkMTY0YzU1YTA3ZmM4Mzg='
|
||||
|
||||
New-Item -ItemType Directory -Path $exportRoot -Force | Out-Null
|
||||
|
||||
$allLogs = Get-WinEvent -ListLog * -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.RecordCount -gt 0 -and $_.LogFilePath }
|
||||
|
||||
$exportCount = 0
|
||||
foreach ($log in $allLogs) {
|
||||
try {
|
||||
# Sanitise log name to safe filename
|
||||
$safeName = $log.LogName -replace '[\\/:*?"<>|]', '_'
|
||||
$exportPath = Join-Path $exportRoot "$safeName.evtx"
|
||||
$session = New-Object System.Diagnostics.Eventing.Reader.EventLogSession
|
||||
$session.ExportLog($log.LogName,
|
||||
[System.Diagnostics.Eventing.Reader.PathType]::LogName,
|
||||
'*',
|
||||
$exportPath)
|
||||
$exportCount++
|
||||
} catch {}
|
||||
}
|
||||
|
||||
Write-Host (" Exported {0} log(s) to temp folder." -f $exportCount) -ForegroundColor Gray
|
||||
|
||||
# ── STEP 2: Compress ────────────────────────────────────────
|
||||
Write-Host " Compressing archive..." -ForegroundColor DarkYellow
|
||||
try {
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
[System.IO.Compression.ZipFile]::CreateFromDirectory($exportRoot, $zipPath)
|
||||
$zipSizeMB = [math]::Round((Get-Item $zipPath).Length / 1MB, 2)
|
||||
Write-Host (" Archive ready: {0} ({1} MB)" -f (Split-Path $zipPath -Leaf), $zipSizeMB) -ForegroundColor Gray
|
||||
} catch {
|
||||
Write-Host " Compression failed: $_" -ForegroundColor Red
|
||||
Write-Host " Aborting event log wipe to protect data." -ForegroundColor Red
|
||||
break
|
||||
}
|
||||
|
||||
# ── STEP 3: Upload ──────────────────────────────────────────
|
||||
Write-Host " Uploading to pebkac.pro..." -ForegroundColor DarkYellow
|
||||
$uploadOk = $false
|
||||
try {
|
||||
# Build multipart form body manually for PS 5.1 compatibility
|
||||
$boundary = [System.Guid]::NewGuid().ToString()
|
||||
$fileBytes = [System.IO.File]::ReadAllBytes($zipPath)
|
||||
$fileName = Split-Path $zipPath -Leaf
|
||||
$encoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
$bodyParts = [System.Collections.Generic.List[byte]]::new()
|
||||
|
||||
# File field header
|
||||
$partHeader = $encoding.GetBytes(
|
||||
"--$boundary`r`nContent-Disposition: form-data; name=`"file`"; filename=`"$fileName`"`r`nContent-Type: application/zip`r`n`r`n"
|
||||
)
|
||||
$bodyParts.AddRange($partHeader)
|
||||
$bodyParts.AddRange($fileBytes)
|
||||
|
||||
# Closing boundary
|
||||
$closingBoundary = $encoding.GetBytes("`r`n--$boundary--`r`n")
|
||||
$bodyParts.AddRange($closingBoundary)
|
||||
|
||||
$response = Invoke-WebRequest `
|
||||
-Uri $uploadUrl `
|
||||
-Method POST `
|
||||
-Headers @{ authorization = $uploadToken; 'x-zipline-original-name' = 'true' } `
|
||||
-ContentType "multipart/form-data; boundary=$boundary" `
|
||||
-Body $bodyParts.ToArray() `
|
||||
-UseBasicParsing `
|
||||
-ErrorAction Stop
|
||||
|
||||
if ($response.StatusCode -in 200,201,204) {
|
||||
$uploadOk = $true
|
||||
Write-Host (" Upload OK (HTTP {0})" -f $response.StatusCode) -ForegroundColor Green
|
||||
|
||||
# Zipline returns { files: [ { url: "..." } ] }
|
||||
try {
|
||||
$respJson = $response.Content | ConvertFrom-Json -ErrorAction SilentlyContinue
|
||||
if ($respJson.files -and $respJson.files.Count -gt 0 -and $respJson.files[0].url) {
|
||||
Write-Host " File URL : $($respJson.files[0].url)" -ForegroundColor Cyan
|
||||
}
|
||||
} catch {}
|
||||
} else {
|
||||
Write-Host (" Upload returned HTTP {0} — aborting wipe." -f $response.StatusCode) -ForegroundColor Red
|
||||
}
|
||||
} catch {
|
||||
Write-Host " Upload FAILED: $_" -ForegroundColor Red
|
||||
Write-Host " Event logs NOT cleared — backup is in: $exportRoot" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# ── STEP 4: Wipe only if upload succeeded ───────────────────
|
||||
if ($uploadOk) {
|
||||
foreach ($log in $allLogs) {
|
||||
try {
|
||||
[System.Diagnostics.Eventing.Reader.EventLogSession]::GlobalSession.ClearLog($log.LogName)
|
||||
} catch {}
|
||||
}
|
||||
$freed += $item.Size
|
||||
Write-Host " Event logs cleared." -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " Skipping wipe — upload did not confirm success." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# ── STEP 5: Cleanup temp export folder (zip stays until reboot) ──
|
||||
try {
|
||||
Remove-Item -Path $exportRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||
} catch {}
|
||||
}
|
||||
|
||||
'IISLogs' {
|
||||
if (Test-Path $item.Path) {
|
||||
$cutoff = (Get-Date).AddDays(-30)
|
||||
Get-ChildItem -Path $item.Path -Recurse -Force -File -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.LastWriteTime -lt $cutoff } |
|
||||
Remove-Item -Force -ErrorAction SilentlyContinue
|
||||
$freed += $item.Size
|
||||
Write-Host " done (files >30 days removed)." -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " path not found, skipped." -ForegroundColor DarkGray
|
||||
}
|
||||
}
|
||||
|
||||
'WER' {
|
||||
if (Test-Path $item.Path) {
|
||||
Get-ChildItem -Path $item.Path -Recurse -Force -ErrorAction SilentlyContinue |
|
||||
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
|
||||
$freed += $item.Size
|
||||
Write-Host " done." -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " path not found, skipped." -ForegroundColor DarkGray
|
||||
}
|
||||
}
|
||||
|
||||
'MiniDumps' {
|
||||
if (Test-Path $item.Path) {
|
||||
Get-ChildItem -Path $item.Path -Filter "*.dmp" -Force -ErrorAction SilentlyContinue |
|
||||
Remove-Item -Force -ErrorAction SilentlyContinue
|
||||
$freed += $item.Size
|
||||
Write-Host " done." -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " path not found, skipped." -ForegroundColor DarkGray
|
||||
}
|
||||
}
|
||||
|
||||
'PrefetchCache' {
|
||||
if (Test-Path $item.Path) {
|
||||
Get-ChildItem -Path $item.Path -Filter "*.pf" -Force -ErrorAction SilentlyContinue |
|
||||
Remove-Item -Force -ErrorAction SilentlyContinue
|
||||
$freed += $item.Size
|
||||
Write-Host " done." -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " disabled or not found, skipped." -ForegroundColor DarkGray
|
||||
}
|
||||
}
|
||||
|
||||
'DeliveryOpt' {
|
||||
try {
|
||||
$doSvc = Get-Service -Name 'DoSvc' -ErrorAction SilentlyContinue
|
||||
if ($doSvc -and $doSvc.Status -eq 'Running') {
|
||||
Stop-Service -Name 'DoSvc' -Force -ErrorAction SilentlyContinue
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
if (Test-Path $item.Path) {
|
||||
Get-ChildItem -Path $item.Path -Recurse -Force -ErrorAction SilentlyContinue |
|
||||
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
if ($doSvc -and $doSvc.Status -ne 'Running') {
|
||||
Start-Service -Name 'DoSvc' -ErrorAction SilentlyContinue
|
||||
}
|
||||
$freed += $item.Size
|
||||
Write-Host " done." -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host " failed: $_" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Write-Host " ERROR: $_" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# SUMMARY
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
$driveAfter = Get-PSDrive C
|
||||
$freeGBafter = [math]::Round($driveAfter.Free / 1GB, 2)
|
||||
|
||||
Write-Host ""
|
||||
Write-Host " ╔══════════════════════════════════════════════════════════╗" -ForegroundColor DarkCyan
|
||||
Write-Host " ║ SUMMARY ║" -ForegroundColor DarkCyan
|
||||
Write-Host " ╚══════════════════════════════════════════════════════════╝" -ForegroundColor DarkCyan
|
||||
Write-Host ""
|
||||
Write-Host (" Free before : {0,8} GB" -f $freeGB) -ForegroundColor Gray
|
||||
Write-Host (" Free after : {0,8} GB" -f $freeGBafter) -ForegroundColor Green
|
||||
Write-Host (" Recovered : {0,10}" -f (Format-Size $freed)) -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host " Done. Belt strong." -ForegroundColor DarkCyan
|
||||
Write-Host ""
|
||||
837
Powershell/Invoke-DiskSpaceReport.ps1
Normal file
837
Powershell/Invoke-DiskSpaceReport.ps1
Normal file
@@ -0,0 +1,837 @@
|
||||
#Requires -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
C: Drive Disk Space Report — generates a self-contained HTML report for stakeholders.
|
||||
|
||||
.DESCRIPTION
|
||||
Scans the C: drive across all common space consumers and produces a polished,
|
||||
printable HTML report. No cleanup is performed. Safe to run at any time.
|
||||
|
||||
.NOTES
|
||||
Supports: Windows Server 2016, 2019, 2022, 2025
|
||||
Run as: Administrator
|
||||
Output: HTML file on the Desktop (or path specified by -OutputPath)
|
||||
Author: SBCIT
|
||||
#>
|
||||
|
||||
param(
|
||||
[string]$OutputPath = "$env:USERPROFILE\Desktop",
|
||||
[string]$ClientName = ""
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'SilentlyContinue'
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# HELPERS
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
function Format-Size {
|
||||
param([long]$Bytes)
|
||||
if ($Bytes -ge 1GB) { return "{0:N2} GB" -f ($Bytes / 1GB) }
|
||||
if ($Bytes -ge 1MB) { return "{0:N2} MB" -f ($Bytes / 1MB) }
|
||||
if ($Bytes -ge 1KB) { return "{0:N2} KB" -f ($Bytes / 1KB) }
|
||||
return "$Bytes B"
|
||||
}
|
||||
|
||||
function Get-FolderSize {
|
||||
param([string]$Path)
|
||||
if (-not (Test-Path $Path)) { return 0 }
|
||||
try {
|
||||
(Get-ChildItem -Path $Path -Recurse -Force -File -ErrorAction SilentlyContinue |
|
||||
Measure-Object -Property Length -Sum).Sum
|
||||
} catch { 0 }
|
||||
}
|
||||
|
||||
function Get-RecycleBinSize {
|
||||
$total = 0
|
||||
try {
|
||||
$shell = New-Object -ComObject Shell.Application
|
||||
$recycle = $shell.Namespace(0xA)
|
||||
foreach ($item in $recycle.Items()) { try { $total += $item.Size } catch {} }
|
||||
} catch {}
|
||||
return $total
|
||||
}
|
||||
|
||||
function Get-SeverityClass {
|
||||
param([long]$Bytes)
|
||||
if ($Bytes -ge 1GB) { return "sev-critical" }
|
||||
if ($Bytes -ge 200MB) { return "sev-warning" }
|
||||
if ($Bytes -ge 10MB) { return "sev-minor" }
|
||||
return "sev-ok"
|
||||
}
|
||||
|
||||
function Get-SeverityLabel {
|
||||
param([long]$Bytes)
|
||||
if ($Bytes -ge 1GB) { return "High" }
|
||||
if ($Bytes -ge 200MB) { return "Medium" }
|
||||
if ($Bytes -ge 10MB) { return "Low" }
|
||||
return "Minimal"
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# CONSOLE PROGRESS
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
Write-Host ""
|
||||
Write-Host " SBCIT // Disk Space Report Generator" -ForegroundColor DarkCyan
|
||||
Write-Host " Scanning $env:COMPUTERNAME — please wait...`n" -ForegroundColor Gray
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# DRIVE STATE
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
$drive = Get-PSDrive C
|
||||
$driveTotal = $drive.Used + $drive.Free
|
||||
$driveFree = $drive.Free
|
||||
$driveUsed = $drive.Used
|
||||
$freePct = [math]::Round(($driveFree / $driveTotal) * 100, 1)
|
||||
$usedPct = [math]::Round(($driveUsed / $driveTotal) * 100, 1)
|
||||
$totalGB = [math]::Round($driveTotal / 1GB, 2)
|
||||
$usedGB = [math]::Round($driveUsed / 1GB, 2)
|
||||
$freeGB = [math]::Round($driveFree / 1GB, 2)
|
||||
|
||||
$driveStatus = if ($freePct -lt 10) { "Critical" } elseif ($freePct -lt 20) { "Low" } else { "Healthy" }
|
||||
$driveStatusClass = if ($freePct -lt 10) { "sev-critical" } elseif ($freePct -lt 20) { "sev-warning" } else { "sev-ok" }
|
||||
|
||||
# OS Version
|
||||
$osInfo = Get-CimInstance Win32_OperatingSystem -ErrorAction SilentlyContinue
|
||||
$osName = if ($osInfo) { $osInfo.Caption } else { "Windows Server" }
|
||||
$osBuild = if ($osInfo) { "Build $($osInfo.BuildNumber)" } else { "" }
|
||||
|
||||
# Uptime
|
||||
$uptime = ""
|
||||
if ($osInfo -and $osInfo.LastBootUpTime) {
|
||||
$span = New-TimeSpan -Start $osInfo.LastBootUpTime -End (Get-Date)
|
||||
$uptime = "$($span.Days)d $($span.Hours)h $($span.Minutes)m"
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# SCAN
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
$findings = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
|
||||
function Add-Finding {
|
||||
param(
|
||||
[string]$Category,
|
||||
[string]$Label,
|
||||
[string]$Path,
|
||||
[long]$Size,
|
||||
[string]$Description,
|
||||
[string]$Note = ""
|
||||
)
|
||||
$findings.Add([PSCustomObject]@{
|
||||
Category = $Category
|
||||
Label = $Label
|
||||
Path = $Path
|
||||
Size = $Size
|
||||
Description = $Description
|
||||
Note = $Note
|
||||
})
|
||||
}
|
||||
|
||||
# Temp Files
|
||||
Add-Finding "Temporary Files" "Windows Temp Folder" "C:\Windows\Temp" (Get-FolderSize "C:\Windows\Temp") "System-wide temporary files created by Windows and applications." ""
|
||||
Add-Finding "Temporary Files" "System Temp ($env:TEMP)" $env:TEMP (Get-FolderSize $env:TEMP) "Temporary files for the current user session." ""
|
||||
Add-Finding "Temporary Files" "User AppData Temp" "C:\Users\$env:USERNAME\AppData\Local\Temp" (Get-FolderSize "C:\Users\$env:USERNAME\AppData\Local\Temp") "Per-user application temporary data." ""
|
||||
|
||||
# Windows Update
|
||||
Add-Finding "Windows Update" "Update Download Cache" "C:\Windows\SoftwareDistribution\Download" (Get-FolderSize "C:\Windows\SoftwareDistribution\Download") "Cached Windows Update downloads. Can be safely cleared when no updates are pending." ""
|
||||
Add-Finding "Windows Update" "WinSxS Component Backups" "C:\Windows\WinSxS\Backup" (Get-FolderSize "C:\Windows\WinSxS\Backup") "Old component backups retained after Windows updates." ""
|
||||
|
||||
# System Logs
|
||||
$cbsSize = Get-FolderSize "C:\Windows\Logs\CBS"
|
||||
Add-Finding "System Logs" "Component-Based Servicing Logs" "C:\Windows\Logs\CBS" $cbsSize "Logs generated during Windows component servicing and updates." ""
|
||||
|
||||
$evtxSize = 0
|
||||
try {
|
||||
$evtxSize = (Get-ChildItem "C:\Windows\System32\winevt\Logs" -Filter "*.evtx" -File -ErrorAction SilentlyContinue |
|
||||
Measure-Object -Property Length -Sum).Sum
|
||||
} catch {}
|
||||
Add-Finding "System Logs" "Windows Event Logs" "C:\Windows\System32\winevt\Logs" $evtxSize "Application, System, and Security event logs." "Backed up to Zipline before clearing."
|
||||
|
||||
# Error Reporting
|
||||
Add-Finding "Error Reporting" "WER Report Queue" "C:\ProgramData\Microsoft\Windows\WER\ReportQueue" (Get-FolderSize "C:\ProgramData\Microsoft\Windows\WER\ReportQueue") "Pending Windows Error Reports awaiting upload to Microsoft." ""
|
||||
Add-Finding "Error Reporting" "WER Report Archive" "C:\ProgramData\Microsoft\Windows\WER\ReportArchive" (Get-FolderSize "C:\ProgramData\Microsoft\Windows\WER\ReportArchive") "Previously sent Windows Error Reports retained locally." ""
|
||||
Add-Finding "Error Reporting" "User Error Reports" "C:\Users\$env:USERNAME\AppData\Local\Microsoft\Windows\WER" (Get-FolderSize "C:\Users\$env:USERNAME\AppData\Local\Microsoft\Windows\WER") "Per-user application crash reports." ""
|
||||
|
||||
# Crash Dumps
|
||||
$miniDump = Get-FolderSize "C:\Windows\Minidump"
|
||||
$memDump = if (Test-Path "C:\Windows\MEMORY.DMP") { (Get-Item "C:\Windows\MEMORY.DMP").Length } else { 0 }
|
||||
Add-Finding "Crash Dumps" "Minidump Files" "C:\Windows\Minidump" $miniDump "Small memory dumps generated when the system encounters a critical error." ""
|
||||
Add-Finding "Crash Dumps" "Full Memory Dump" "C:\Windows\MEMORY.DMP" $memDump "Complete RAM snapshot from last system crash. Large file — only present after a BSOD." ""
|
||||
|
||||
# Delivery Optimisation
|
||||
Add-Finding "Delivery Optimisation" "DO Peer Cache" "C:\Windows\SoftwareDistribution\DeliveryOptimization" (Get-FolderSize "C:\Windows\SoftwareDistribution\DeliveryOptimization") "Windows Update peer-to-peer delivery cache." ""
|
||||
Add-Finding "Delivery Optimisation" "DO Network Service Cache" "C:\Windows\ServiceProfiles\NetworkService\AppData\Local\Microsoft\Windows\DeliveryOptimization" (Get-FolderSize "C:\Windows\ServiceProfiles\NetworkService\AppData\Local\Microsoft\Windows\DeliveryOptimization") "Delivery Optimisation metadata cache." ""
|
||||
|
||||
# IIS Logs
|
||||
foreach ($iisPath in @("C:\inetpub\logs\LogFiles","C:\Windows\System32\LogFiles\W3SVC1")) {
|
||||
$sz = Get-FolderSize $iisPath
|
||||
if ($sz -gt 0) {
|
||||
Add-Finding "IIS Web Server Logs" "IIS Logs ($iisPath)" $iisPath $sz "Internet Information Services access and error logs." "Cleanup removes files older than 30 days."
|
||||
}
|
||||
}
|
||||
|
||||
# Recycle Bin
|
||||
Add-Finding "Recycle Bin" "C: Recycle Bin" 'C:\$Recycle.Bin' (Get-RecycleBinSize) "Files deleted by users but not yet permanently removed." ""
|
||||
|
||||
# Cache
|
||||
Add-Finding "Cache" "Thumbnail Cache" "C:\Users\$env:USERNAME\AppData\Local\Microsoft\Windows\Explorer" (Get-FolderSize "C:\Users\$env:USERNAME\AppData\Local\Microsoft\Windows\Explorer") "Cached image thumbnails. Rebuilds automatically when browsing folders." ""
|
||||
Add-Finding "Cache" "Font Cache" "C:\Windows\ServiceProfiles\LocalService\AppData\Local\FontCache" (Get-FolderSize "C:\Windows\ServiceProfiles\LocalService\AppData\Local\FontCache") "Font rendering cache. Rebuilds automatically on next boot." ""
|
||||
|
||||
# Installer Cache
|
||||
$installerCache = Get-FolderSize "C:\Windows\Installer\`$PatchCache`$"
|
||||
Add-Finding "Installer Cache" "MSI Patch Cache" "C:\Windows\Installer\`$PatchCache`$" $installerCache "Cached MSI installer patches. Clearing may affect application repair." "⚠ Verify before removing."
|
||||
|
||||
# Old Profiles
|
||||
$systemProfiles = @('Administrator','Default','Default User','Public','All Users','LocalService','NetworkService','systemprofile')
|
||||
$oldProfiles = Get-ChildItem "C:\Users" -Directory -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.Name -notin $systemProfiles -and $_.Name -ne $env:USERNAME }
|
||||
foreach ($prof in $oldProfiles) {
|
||||
$sz = Get-FolderSize $prof.FullName
|
||||
Add-Finding "User Profiles" "Profile: $($prof.Name)" $prof.FullName $sz "User profile folder for an account that may no longer be active." "⚠ Verify account status before removing."
|
||||
}
|
||||
|
||||
# Legacy
|
||||
Add-Finding "Legacy" "Downloaded Program Files" "C:\Windows\Downloaded Program Files" (Get-FolderSize "C:\Windows\Downloaded Program Files") "Legacy ActiveX and Java components. Generally safe to clear on modern servers." ""
|
||||
|
||||
# Filter zero-size findings
|
||||
$findings = $findings | Where-Object { $_.Size -gt 0 }
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# DERIVED STATS
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
$totalRecoverable = ($findings | Measure-Object -Property Size -Sum).Sum
|
||||
$recoverablePct = if ($driveTotal -gt 0) { [math]::Round(($totalRecoverable / $driveTotal) * 100, 1) } else { 0 }
|
||||
$projectedFreeGB = [math]::Round(($driveFree + $totalRecoverable) / 1GB, 2)
|
||||
$projectedFreePct = [math]::Round((($driveFree + $totalRecoverable) / $driveTotal) * 100, 1)
|
||||
|
||||
$categoryGroups = $findings | Group-Object Category | Sort-Object { ($_.Group | Measure-Object -Property Size -Sum).Sum } -Descending
|
||||
$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
|
||||
$fileStamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||
$reportFile = Join-Path $OutputPath "$($env:COMPUTERNAME)_DiskReport_$fileStamp.html"
|
||||
$reportTitle = if ($ClientName) { "$ClientName — $($env:COMPUTERNAME)" } else { $env:COMPUTERNAME }
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# BUILD HTML
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
$rowsHtml = [System.Text.StringBuilder]::new()
|
||||
foreach ($group in $categoryGroups) {
|
||||
$groupTotal = ($group.Group | Measure-Object -Property Size -Sum).Sum
|
||||
$isFirst = $true
|
||||
$rowCount = $group.Group.Count
|
||||
foreach ($item in ($group.Group | Sort-Object Size -Descending)) {
|
||||
$sev = Get-SeverityClass $item.Size
|
||||
$sevLabel = Get-SeverityLabel $item.Size
|
||||
$sizeStr = Format-Size $item.Size
|
||||
$noteHtml = if ($item.Note) { "<span class='note'>$([System.Web.HttpUtility]::HtmlEncode($item.Note))</span>" } else { "" }
|
||||
if ($isFirst) {
|
||||
$catCell = "<td class='cat-cell' rowspan='$rowCount'>$([System.Web.HttpUtility]::HtmlEncode($group.Name))<span class='cat-total'>$(Format-Size $groupTotal)</span></td>"
|
||||
$isFirst = $false
|
||||
} else {
|
||||
$catCell = ""
|
||||
}
|
||||
[void]$rowsHtml.AppendLine("
|
||||
<tr>
|
||||
$catCell
|
||||
<td>$([System.Web.HttpUtility]::HtmlEncode($item.Label))<br><span class='path'>$([System.Web.HttpUtility]::HtmlEncode($item.Path))</span></td>
|
||||
<td class='desc-cell'>$([System.Web.HttpUtility]::HtmlEncode($item.Description)) $noteHtml</td>
|
||||
<td class='size-cell $sev'>$sizeStr</td>
|
||||
<td class='sev-badge-cell'><span class='badge $sev'>$sevLabel</span></td>
|
||||
</tr>")
|
||||
}
|
||||
}
|
||||
|
||||
$barUsed = [math]::Round($usedPct)
|
||||
$barUsedColor = if ($usedPct -gt 90) { "#e05252" } elseif ($usedPct -gt 75) { "#e09a3a" } else { "#4a7fb5" }
|
||||
|
||||
$html = @"
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Disk Space Report — $reportTitle</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600&family=IBM+Plex+Sans:wght@300;400;500;600;700&display=swap');
|
||||
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
:root {
|
||||
--bg: #f4f5f7;
|
||||
--surface: #ffffff;
|
||||
--border: #dde1e9;
|
||||
--text: #1a2033;
|
||||
--text-muted: #6b7591;
|
||||
--accent: #1a4f8a;
|
||||
--accent-lt: #e8eff8;
|
||||
--red: #c0392b;
|
||||
--red-lt: #fdecea;
|
||||
--amber: #b7621a;
|
||||
--amber-lt: #fef3e2;
|
||||
--blue: #1a4f8a;
|
||||
--blue-lt: #e8eff8;
|
||||
--green: #1e6b45;
|
||||
--green-lt: #e6f5ed;
|
||||
--mono: 'IBM Plex Mono', monospace;
|
||||
--sans: 'IBM Plex Sans', system-ui, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--sans);
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.page-wrap {
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 40px 32px 60px;
|
||||
}
|
||||
|
||||
/* ── HEADER ── */
|
||||
.report-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
margin-bottom: 36px;
|
||||
padding-bottom: 28px;
|
||||
border-bottom: 2px solid var(--accent);
|
||||
}
|
||||
.brand { display: flex; align-items: center; gap: 14px; }
|
||||
.brand-logo {
|
||||
width: 44px; height: 44px;
|
||||
background: var(--accent);
|
||||
border-radius: 8px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
color: #fff;
|
||||
font-family: var(--mono);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.03em;
|
||||
text-align: center;
|
||||
line-height: 1.3;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.brand-text { }
|
||||
.brand-text h1 {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: var(--text);
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.brand-text .subtitle {
|
||||
font-size: 13px;
|
||||
color: var(--text-muted);
|
||||
margin-top: 2px;
|
||||
}
|
||||
.report-meta {
|
||||
text-align: right;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.report-meta .meta-line {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
font-family: var(--mono);
|
||||
line-height: 1.8;
|
||||
}
|
||||
.report-meta .meta-line strong {
|
||||
color: var(--text);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ── SUMMARY CARDS ── */
|
||||
.cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 16px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
.card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
padding: 20px 22px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0;
|
||||
height: 3px;
|
||||
background: var(--accent);
|
||||
}
|
||||
.card.warn::before { background: #e09a3a; }
|
||||
.card.crit::before { background: #e05252; }
|
||||
.card.good::before { background: #2e9e66; }
|
||||
.card-label {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.card-value {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
font-family: var(--mono);
|
||||
color: var(--text);
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 1;
|
||||
}
|
||||
.card-sub {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
margin-top: 4px;
|
||||
}
|
||||
.card-badge {
|
||||
display: inline-block;
|
||||
margin-top: 8px;
|
||||
padding: 2px 10px;
|
||||
border-radius: 20px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
.badge-crit { background: var(--red-lt); color: var(--red); }
|
||||
.badge-warn { background: var(--amber-lt); color: var(--amber); }
|
||||
.badge-good { background: var(--green-lt); color: var(--green); }
|
||||
|
||||
/* ── DRIVE BAR ── */
|
||||
.drive-bar-wrap {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
padding: 22px 26px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
.drive-bar-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.drive-bar-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.07em;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.drive-bar-legend {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
font-family: var(--mono);
|
||||
}
|
||||
.drive-bar-legend span strong { color: var(--text); }
|
||||
.bar-track {
|
||||
width: 100%;
|
||||
height: 18px;
|
||||
background: #e8eaf0;
|
||||
border-radius: 9px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
.bar-used {
|
||||
height: 100%;
|
||||
border-radius: 9px;
|
||||
transition: width 0.4s ease;
|
||||
position: relative;
|
||||
}
|
||||
.bar-recoverable-marker {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
background: repeating-linear-gradient(
|
||||
135deg,
|
||||
rgba(255,255,255,0.25) 0px,
|
||||
rgba(255,255,255,0.25) 4px,
|
||||
transparent 4px,
|
||||
transparent 8px
|
||||
);
|
||||
border-right: 2px dashed rgba(255,255,255,0.6);
|
||||
}
|
||||
.bar-labels {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 8px;
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
font-family: var(--mono);
|
||||
}
|
||||
.bar-label-recoverable {
|
||||
color: #e09a3a;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ── SECTION TITLE ── */
|
||||
.section-title {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.09em;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.section-title::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: var(--border);
|
||||
}
|
||||
|
||||
/* ── TABLE ── */
|
||||
.findings-table-wrap {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
thead th {
|
||||
background: #1a2033;
|
||||
color: #a8b4cc;
|
||||
font-size: 10.5px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
padding: 12px 16px;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
tbody tr {
|
||||
border-bottom: 1px solid var(--border);
|
||||
transition: background 0.12s;
|
||||
}
|
||||
tbody tr:last-child { border-bottom: none; }
|
||||
tbody tr:hover { background: #f8f9fc; }
|
||||
td {
|
||||
padding: 12px 16px;
|
||||
vertical-align: top;
|
||||
font-size: 13px;
|
||||
}
|
||||
.cat-cell {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
white-space: nowrap;
|
||||
vertical-align: top;
|
||||
border-right: 2px solid var(--accent-lt);
|
||||
background: var(--accent-lt);
|
||||
width: 160px;
|
||||
}
|
||||
.cat-total {
|
||||
display: block;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
color: var(--text-muted);
|
||||
font-family: var(--mono);
|
||||
margin-top: 3px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
.path {
|
||||
font-family: var(--mono);
|
||||
font-size: 10.5px;
|
||||
color: var(--text-muted);
|
||||
display: block;
|
||||
margin-top: 3px;
|
||||
}
|
||||
.desc-cell {
|
||||
color: var(--text-muted);
|
||||
font-size: 12.5px;
|
||||
max-width: 340px;
|
||||
}
|
||||
.note {
|
||||
display: inline-block;
|
||||
margin-top: 4px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--amber);
|
||||
background: var(--amber-lt);
|
||||
padding: 1px 7px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.size-cell {
|
||||
font-family: var(--mono);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
text-align: right;
|
||||
}
|
||||
.sev-badge-cell { width: 80px; text-align: center; }
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 3px 10px;
|
||||
border-radius: 20px;
|
||||
font-size: 10.5px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.sev-critical { color: var(--red); }
|
||||
.sev-warning { color: var(--amber); }
|
||||
.sev-minor { color: var(--blue); }
|
||||
.sev-ok { color: #6b7591; }
|
||||
.badge.sev-critical { background: var(--red-lt); color: var(--red); }
|
||||
.badge.sev-warning { background: var(--amber-lt); color: var(--amber); }
|
||||
.badge.sev-minor { background: var(--blue-lt); color: var(--blue); }
|
||||
.badge.sev-ok { background: #f0f1f4; color: #6b7591; }
|
||||
|
||||
/* ── LEGEND ── */
|
||||
.legend-row {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 28px;
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
align-items: center;
|
||||
}
|
||||
.legend-item { display: flex; align-items: center; gap: 7px; }
|
||||
|
||||
/* ── RECOMMENDATION BOX ── */
|
||||
.rec-box {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-left: 4px solid var(--accent);
|
||||
border-radius: 10px;
|
||||
padding: 20px 24px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
.rec-box h3 {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.07em;
|
||||
color: var(--accent);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.rec-list { list-style: none; }
|
||||
.rec-list li {
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 10px;
|
||||
}
|
||||
.rec-list li:last-child { border-bottom: none; }
|
||||
.rec-icon {
|
||||
flex-shrink: 0;
|
||||
font-size: 13px;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* ── FOOTER ── */
|
||||
.report-footer {
|
||||
margin-top: 44px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid var(--border);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
font-family: var(--mono);
|
||||
}
|
||||
|
||||
/* ── PRINT ── */
|
||||
@media print {
|
||||
body { background: #fff; font-size: 12px; }
|
||||
.page-wrap { padding: 20px; max-width: 100%; }
|
||||
.card-value { font-size: 22px; }
|
||||
tbody tr:hover { background: none; }
|
||||
.findings-table-wrap { box-shadow: none; border: 1px solid #ccc; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page-wrap">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="report-header">
|
||||
<div class="brand">
|
||||
<div class="brand-logo">SBC<br>IT</div>
|
||||
<div class="brand-text">
|
||||
<h1>Disk Space Report</h1>
|
||||
<div class="subtitle">$reportTitle — C: Drive Analysis</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="report-meta">
|
||||
<div class="meta-line"><strong>Host</strong> $($env:COMPUTERNAME)</div>
|
||||
<div class="meta-line"><strong>OS</strong> $osName $osBuild</div>
|
||||
<div class="meta-line"><strong>Uptime</strong> $uptime</div>
|
||||
<div class="meta-line"><strong>Generated</strong> $timestamp</div>
|
||||
<div class="meta-line"><strong>Prepared by</strong> SBCIT</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SUMMARY CARDS -->
|
||||
<div class="cards">
|
||||
<div class="card $(if ($driveStatus -eq 'Critical') {'crit'} elseif ($driveStatus -eq 'Low') {'warn'} else {'good'})">
|
||||
<div class="card-label">Drive Status</div>
|
||||
<div class="card-value">$driveStatus</div>
|
||||
<div class="card-sub">$freePct% free of $totalGB GB total</div>
|
||||
<span class="card-badge $(if ($driveStatus -eq 'Critical') {'badge-crit'} elseif ($driveStatus -eq 'Low') {'badge-warn'} else {'badge-good'})">$driveStatus</span>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-label">Currently Free</div>
|
||||
<div class="card-value">$freeGB<span style="font-size:14px;font-weight:400"> GB</span></div>
|
||||
<div class="card-sub">$freePct% of total capacity</div>
|
||||
</div>
|
||||
<div class="card warn">
|
||||
<div class="card-label">Recoverable Space</div>
|
||||
<div class="card-value">$(Format-Size $totalRecoverable)</div>
|
||||
<div class="card-sub">$recoverablePct% of total capacity</div>
|
||||
</div>
|
||||
<div class="card good">
|
||||
<div class="card-label">Projected Free (After)</div>
|
||||
<div class="card-value">$projectedFreeGB<span style="font-size:14px;font-weight:400"> GB</span></div>
|
||||
<div class="card-sub">$projectedFreePct% if all items cleaned</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DRIVE BAR -->
|
||||
<div class="drive-bar-wrap">
|
||||
<div class="drive-bar-header">
|
||||
<div class="drive-bar-title">C: Drive Capacity</div>
|
||||
<div class="drive-bar-legend">
|
||||
<span><strong>$usedGB GB</strong> used</span>
|
||||
<span><strong>$(Format-Size $totalRecoverable)</strong> recoverable</span>
|
||||
<span><strong>$freeGB GB</strong> free</span>
|
||||
<span><strong>$totalGB GB</strong> total</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bar-track">
|
||||
<div class="bar-used" style="width:${barUsed}%; background:$barUsedColor;">
|
||||
<div class="bar-recoverable-marker" style="right:0; width:$(if ($barUsed -gt 0) { [math]::Round(($totalRecoverable / $driveTotal) * 100, 1) } else { 0 })%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bar-labels">
|
||||
<span>0 GB</span>
|
||||
<span class="bar-label-recoverable">↥ $(Format-Size $totalRecoverable) recoverable</span>
|
||||
<span>$totalGB GB</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- LEGEND -->
|
||||
<div class="legend-row">
|
||||
<span style="font-size:12px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.06em;">Impact:</span>
|
||||
<div class="legend-item"><span class="badge sev-critical">High</span> <span>≥ 1 GB</span></div>
|
||||
<div class="legend-item"><span class="badge sev-warning">Medium</span> <span>200 MB – 1 GB</span></div>
|
||||
<div class="legend-item"><span class="badge sev-minor">Low</span> <span>10 MB – 200 MB</span></div>
|
||||
<div class="legend-item"><span class="badge sev-ok">Minimal</span> <span>< 10 MB</span></div>
|
||||
</div>
|
||||
|
||||
<!-- FINDINGS TABLE -->
|
||||
<div class="section-title">Findings — All Scanned Categories</div>
|
||||
<div class="findings-table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Category</th>
|
||||
<th>Item</th>
|
||||
<th>Description</th>
|
||||
<th style="text-align:right">Size</th>
|
||||
<th style="text-align:center">Impact</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
$($rowsHtml.ToString())
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- RECOMMENDATION BOX -->
|
||||
<div class="section-title">Recommendations</div>
|
||||
<div class="rec-box">
|
||||
<h3>Suggested Actions</h3>
|
||||
<ul class="rec-list">
|
||||
$(
|
||||
$recLines = [System.Text.StringBuilder]::new()
|
||||
if ($totalRecoverable -gt 5GB) {
|
||||
[void]$recLines.AppendLine(" <li><span class='rec-icon'>⚠</span> Immediate cleanup is recommended. Total recoverable space exceeds 5 GB, which may impact server performance and reliability.</li>")
|
||||
} elseif ($totalRecoverable -gt 1GB) {
|
||||
[void]$recLines.AppendLine(" <li><span class='rec-icon'>ℹ</span> Cleanup is advisable at the next available maintenance window. Over 1 GB of recoverable space was found.</li>")
|
||||
} else {
|
||||
[void]$recLines.AppendLine(" <li><span class='rec-icon'>✔</span> No urgent action required. Recoverable space is within acceptable limits.</li>")
|
||||
}
|
||||
if ($freePct -lt 15) {
|
||||
[void]$recLines.AppendLine(" <li><span class='rec-icon'>⚠</span> <strong>Free space is critically low ($freePct%).</strong> Disk pressure at this level can cause service failures, failed backups, and event log interruption. Escalate promptly.</li>")
|
||||
}
|
||||
if ($evtxSize -gt 500MB) {
|
||||
[void]$recLines.AppendLine(" <li><span class='rec-icon'>📋</span> Event logs are consuming $(Format-Size $evtxSize). These will be automatically backed up to secure storage before clearing.</li>")
|
||||
}
|
||||
if ($memDump -gt 0) {
|
||||
[void]$recLines.AppendLine(" <li><span class='rec-icon'>⚠</span> A full memory dump (MEMORY.DMP) was found ($(Format-Size $memDump)). This indicates a past system crash. Recommend reviewing crash cause before removing.</li>")
|
||||
}
|
||||
$wuSize = ($findings | Where-Object { $_.Category -eq 'Windows Update' } | Measure-Object -Property Size -Sum).Sum
|
||||
if ($wuSize -gt 1GB) {
|
||||
[void]$recLines.AppendLine(" <li><span class='rec-icon'>🔄</span> Windows Update cache is $(Format-Size $wuSize). Safe to clear after confirming no updates are pending installation.</li>")
|
||||
}
|
||||
$iisSize = ($findings | Where-Object { $_.Category -eq 'IIS Web Server Logs' } | Measure-Object -Property Size -Sum).Sum
|
||||
if ($iisSize -gt 0) {
|
||||
[void]$recLines.AppendLine(" <li><span class='rec-icon'>📄</span> IIS logs ($( Format-Size $iisSize)) can be reduced by removing files older than 30 days. Consider implementing automated log rotation.</li>")
|
||||
}
|
||||
[void]$recLines.AppendLine(" <li><span class='rec-icon'>🔧</span> Run cleanup via the SBCIT disk cleanup script (<code>Invoke-DiskCleanupScan.ps1</code>) which handles all items above safely with confirmation prompts.</li>")
|
||||
$recLines.ToString()
|
||||
)
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<div class="report-footer">
|
||||
<span>SBCIT Managed Services — Confidential</span>
|
||||
<span>$($env:COMPUTERNAME) — $timestamp</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"@
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# WRITE FILE
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
# Need HttpUtility for HTML encoding — load System.Web
|
||||
Add-Type -AssemblyName System.Web -ErrorAction SilentlyContinue
|
||||
|
||||
$html | Out-File -FilePath $reportFile -Encoding UTF8
|
||||
|
||||
Write-Host ""
|
||||
Write-Host " ✔ Report generated:" -ForegroundColor Green
|
||||
Write-Host " $reportFile" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host (" Total Recoverable : {0}" -f (Format-Size $totalRecoverable)) -ForegroundColor Yellow
|
||||
Write-Host (" Current Free : $freeGB GB ($freePct%)") -ForegroundColor Gray
|
||||
Write-Host (" Projected Free : $projectedFreeGB GB ($projectedFreePct%)") -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# Open in default browser
|
||||
try {
|
||||
Start-Process $reportFile
|
||||
} catch {}
|
||||
BIN
Powershell/Misc/Add_ps1_to_New_context_menu.reg
Normal file
BIN
Powershell/Misc/Add_ps1_to_New_context_menu.reg
Normal file
Binary file not shown.
82
Powershell/Misc/FAQ.md
Normal file
82
Powershell/Misc/FAQ.md
Normal file
@@ -0,0 +1,82 @@
|
||||
PowerShell FAQ
|
||||
==============
|
||||
|
||||
What is PowerShell?
|
||||
-------------------
|
||||
PowerShell is a task automation and configuration management framework from Microsoft, consisting of a command-line shell and associated scripting language.
|
||||
|
||||
Why use PowerShell?
|
||||
-------------------
|
||||
* **it's powerful**: fully control your computer
|
||||
* **it's cross-platform**: available for Linux, Mac OS and Windows
|
||||
* **it's open-source and free**: see the Github repository at https://github.com/PowerShell/PowerShell
|
||||
* **it's easy to learn**: see the tutorial at https://www.guru99.com/powershell-tutorial.html
|
||||
* **it's fully documented**: see the official docs at https://docs.microsoft.com/en-us/powershell/
|
||||
|
||||
How to get PowerShell?
|
||||
----------------------
|
||||
* **On Windows 7 and newer** PowerShell is provided by default. However, script execution is **not allowed by default** (execution policy is "restricted"). To enable this, enter as administrator:
|
||||
```
|
||||
$ Set-ExecutionPolicy RemoteSigned
|
||||
```
|
||||
* **On CentOS, Debian, Docker, Fedora, macOS, openSUSE, Red Hat, Ubuntu** visit https://github.com/PowerShell/PowerShell for installation.
|
||||
* **Want to use Snaps?** Install the PowerShell snap by executing:
|
||||
```
|
||||
$ snap install PowerShell
|
||||
$ ln -s /snap/bin/pwsh /usr/bin/pwsh
|
||||
```
|
||||
|
||||
How to get the PowerShell Scripts?
|
||||
----------------------------------
|
||||
* Git users execute: `$ git clone https://github.com/fleschutz/PowerShell`
|
||||
* otherwise download it from: https://github.com/fleschutz/PowerShell/archive/master.zip
|
||||
|
||||
|
||||
Why do some Scripts show gibberish characters?
|
||||
----------------------------------------------
|
||||
Those PowerShell scripts are using Unicode input & output! Use a modern console supporting UTF-8 such as Windows Terminal, please.
|
||||
|
||||
|
||||
How to set PowerShell as My Default Shell on Linux?
|
||||
---------------------------------------------------
|
||||
Make sure PowerShell is installed, then execute: `chsh -s /usr/bin/pwsh <username>`. In case you experience an "invalid shell" error, add "/usr/bin/pwsh" to /etc/shells.
|
||||
|
||||
|
||||
How to add the Scripts to the Search Path?
|
||||
------------------------------------------
|
||||
Want to use the PowerShell scripts everywhere on the command-line? Then you need to add the Scripts/ subfolder to the search path:
|
||||
|
||||
* **On Linux using Bash:** edit .profile in your home directory and add the line: PATH="$PATH:/path/to/PowerShell/Scripts"
|
||||
* **On Windows:** open the environment variables dialogue and add the full path to Scripts/ to the system environment variable "Path"
|
||||
|
||||
|
||||
How to use PowerShell in Context Menus?
|
||||
---------------------------------------
|
||||
* to enable "right-click > New > Windows PowerShell Script" execute `Add_ps1_to_New_context_menu.reg` in subfolder [Misc/](Misc)
|
||||
* to disable this execute `Remove_ps1_from_New_context_menu.reg` in subfolder [Misc/](Misc)
|
||||
|
||||
|
||||
How to edit the PowerShell Scripts?
|
||||
-----------------------------------
|
||||
* use *PowerShell ISE* (Integrated Scripting Environment) to write, test and debug scripts (available for free on Windows only).
|
||||
* use *Visual Studio Code* supporting syntax highlighting, on-the-fly problem checking and an integrated PowerShell Console (available for free on Linux, Mac OS and Windows).
|
||||
* or simply use your *favorite text editor*
|
||||
|
||||
How to write good PowerShell Scripts?
|
||||
-------------------------------------
|
||||
Good PowerShell scripts are user-friendly and platform-independant. As a guideline follow these rules, please:
|
||||
|
||||
1. the filename is named using the `<verb>-<object>.ps1` scheme
|
||||
2. the encoding is UTF-8-BOM to support and use Unicode characters (including emojis where appropriate)
|
||||
3. the script has execute file permissions: chmod a+rx <file> (for Linux support)
|
||||
4. provide a comment-based help with syntax, description, link, author, and license
|
||||
5. check the requirements (e.g. #Requires -RunAsAdministrator, or #Requires -Version 3)
|
||||
6. prefer command-line options, else ask the user for help
|
||||
7. recommended is `Set-StrictMode -Version Latest` to enable additional error checking
|
||||
8. for readibility use UpperCamelCase for variables and functions, lowerCamelCase for everything else
|
||||
9. on error call write-error with keyword "ERROR:" (to support log parsers) and exit the error code (mostly 1)
|
||||
10. on success exit with error code 0 (exit 0)
|
||||
|
||||
Your Question is not answered here?
|
||||
-----------------------------------
|
||||
Send your question to: markus [at] fleschutz [dot] de
|
||||
BIN
Powershell/Misc/Remove_ps1_from_New_context_menu.reg
Normal file
BIN
Powershell/Misc/Remove_ps1_from_New_context_menu.reg
Normal file
Binary file not shown.
BIN
Powershell/Misc/powershell_black_icon_64x64.png
Normal file
BIN
Powershell/Misc/powershell_black_icon_64x64.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
BIN
Powershell/Misc/powershell_icon_256x256.png
Normal file
BIN
Powershell/Misc/powershell_icon_256x256.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
BIN
Powershell/Misc/powershell_icon_64x64.png
Normal file
BIN
Powershell/Misc/powershell_icon_64x64.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,44 @@
|
||||
# Script to add user to an AzureAD role
|
||||
|
||||
<#
|
||||
You can find a list of available roles in the following Microsoft article
|
||||
https://docs.microsoft.com/en-us/azure/active-directory/active-directory-assign-admin-roles-azure-portal
|
||||
Double check using Get-AzureADDirectoryRole as they don't always have the same name in PowerShell as the GUI
|
||||
|
||||
Built from the code example on the following Mircosoft page
|
||||
https://docs.microsoft.com/en-us/powershell/module/azuread/add-azureaddirectoryrolemember?view=azureadps-2.0
|
||||
#>
|
||||
|
||||
|
||||
# User UPN to assign role to
|
||||
$roleUser = ''
|
||||
|
||||
# Role Name to Assign
|
||||
$roleName = ''
|
||||
|
||||
|
||||
# Import AzureAD module and Connect
|
||||
Import-Module AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Fetch user to assign to role
|
||||
$roleMember = Get-AzureADUser -ObjectId $roleUser
|
||||
|
||||
# Fetch role instance
|
||||
$role = Get-AzureADDirectoryRole | Where-Object {$_.displayName -eq $roleName}
|
||||
|
||||
# If role instance does not exist, instantiate it based on the role template
|
||||
if (!($role)) {
|
||||
# Instantiate an instance of the role template
|
||||
$roleTemplate = Get-AzureADDirectoryRoleTemplate | Where-Object {$_.displayName -eq $roleName}
|
||||
Enable-AzureADDirectoryRole -RoleTemplateId $roleTemplate.ObjectId
|
||||
|
||||
# Fetch role instance again
|
||||
$role = Get-AzureADDirectoryRole | Where-Object {$_.displayName -eq $roleName}
|
||||
}
|
||||
|
||||
# Add user to role
|
||||
Add-AzureADDirectoryRoleMember -ObjectId $role.ObjectId -RefObjectId $roleMember.ObjectId
|
||||
|
||||
# Fetch role membership for role to confirm
|
||||
Get-AzureADDirectoryRoleMember -ObjectId $role.ObjectId | Get-AzureADUser
|
||||
@@ -0,0 +1,45 @@
|
||||
# Bulk add a new licence to users on the basis of what licence they currently have.
|
||||
#
|
||||
# An updated version of my previous MSOL script, now using AzureAD.
|
||||
# This is useful for something like adding Office 365 ATP to everyone who currently has E3, for example.
|
||||
#
|
||||
# List of available SKUs can be obtained with (Get-AzureADSubscribedSku).SkuPartNumber
|
||||
#
|
||||
|
||||
# What licence do the users currently have?
|
||||
$existingLicence = 'ENTERPRISEPACK'
|
||||
|
||||
# What licence are we adding?
|
||||
$licenceToAdd = 'ATP_ENTERPRISE'
|
||||
|
||||
# Import AzureAD module and connect
|
||||
Import-Module AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Get all available licence skus
|
||||
$allSkus = Get-AzureADSubscribedSku
|
||||
|
||||
# Get sku ID for existing licence
|
||||
$existingSkuID = ($allSkus | Where-Object {$_.SkuPartNumber -eq $existingLicence}).SkuId
|
||||
|
||||
# Get sku ID for new licence
|
||||
$newSkuID = ($allSkus | Where-Object {$_.SkuPartNumber -eq $licenceToAdd}).SkuId
|
||||
|
||||
# Find everyone who has the existing licence but not the licence we're adding
|
||||
$users = Get-AzureADUser -All $true | Where-Object {$_.AssignedLicenses.SkuId -match $existingSkuID -and !($_.AssignedLicenses.SkuId -match $newSkuID)}
|
||||
|
||||
# Create a new licence object for the licence we're adding
|
||||
$newLicense = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense
|
||||
$newLicense.SkuId = $newSkuID
|
||||
|
||||
# Create a new assigned licenses object and add the licence we're adding to add licenses
|
||||
$newLicenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses
|
||||
$newLicenses.AddLicenses = $newLicense
|
||||
|
||||
# Add the new licence to each user in the list
|
||||
foreach ($user in $users) {
|
||||
Set-AzureADUserLicense -ObjectId $user.UserPrincipalName -AssignedLicenses $newLicenses
|
||||
}
|
||||
|
||||
# Disconnect from AzureAD
|
||||
Disconnect-AzureAD
|
||||
@@ -0,0 +1,53 @@
|
||||
# Bulk add additional licences to a list of users.
|
||||
#
|
||||
# An updated version of my previous MSOL script, now using AzureAD.
|
||||
#
|
||||
# List of available SKUs can be obtained with (Get-AzureADSubscribedSku).SkuPartNumber
|
||||
#
|
||||
|
||||
# Where is the list of user UPN's?
|
||||
$userListPath = 'C:\Temp\UserList.txt'
|
||||
|
||||
# What licences are we adding?
|
||||
$licencesToAdd = @('ENTERPRISEPACK','ATP_ENTERPRISE','EMSPREMIUM')
|
||||
|
||||
# Import AzureAD module and connect
|
||||
Import-Module AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Import list of users from file
|
||||
$userList = Get-Content -Path $userListPath | Sort-Object
|
||||
|
||||
# Get all available licence skus
|
||||
$newSkuIDs = (Get-AzureADSubscribedSku | Where-Object {$_.SkuPartNumber -in $licencesToAdd}).SkuId
|
||||
|
||||
# Create a licenses object
|
||||
$licenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses
|
||||
|
||||
# Add the licences to add to the licences object
|
||||
foreach ($newSkuID in $newSkuIDs) {
|
||||
$newLicense = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense
|
||||
$newLicense.SkuId = $newSkuID
|
||||
$licenses.AddLicenses += $newLicense
|
||||
}
|
||||
|
||||
# Add the licenses
|
||||
foreach ($username in $userList) {
|
||||
try {
|
||||
$user = Get-AzureADUser -ObjectId $username -ErrorAction Stop
|
||||
if ($user.AccountEnabled -eq $true) {
|
||||
Set-AzureADUserLicense -ObjectId $user.UserPrincipalName -AssignedLicenses $licenses -ErrorAction Stop
|
||||
Write-Output -InputObject ('Licence(s) added for user account ' + $user.UserPrincipalName + '.')
|
||||
}
|
||||
else {
|
||||
Write-Output -InputObject ('User account ' + $user.UserPrincipalName + ' is disabled.')
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Output -InputObject ('There was a problem updating licences for user account ' + $user.UserPrincipalName + '.')
|
||||
Write-Output -InputObject $Error[0]
|
||||
}
|
||||
}
|
||||
|
||||
# Disconnect from AzureAD
|
||||
Disconnect-AzureAD
|
||||
@@ -0,0 +1,58 @@
|
||||
# Script to add multiple users to multiple AzureAD roles
|
||||
|
||||
<#
|
||||
You can find a list of available roles in the following Microsoft article
|
||||
https://docs.microsoft.com/en-us/azure/active-directory/active-directory-assign-admin-roles-azure-portal
|
||||
Double check using Get-AzureADDirectoryRole as they don't always have the same name in PowerShell as the GUI
|
||||
|
||||
Built from the code example on the following Mircosoft page
|
||||
https://docs.microsoft.com/en-us/powershell/module/azuread/add-azureaddirectoryrolemember?view=azureadps-2.0
|
||||
#>
|
||||
|
||||
|
||||
# User UPNs to assign roles to
|
||||
$roleUsers = @('')
|
||||
|
||||
# Role Names to Assign
|
||||
$roleNames = @('')
|
||||
|
||||
|
||||
# Import AzureAD module and Connect
|
||||
Import-Module AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Run through the list of users
|
||||
foreach ($roleUser in $roleUsers) {
|
||||
# Fetch user to assign to role
|
||||
$roleMember = Get-AzureADUser -ObjectId $roleUser
|
||||
|
||||
# Run through the list of roles
|
||||
foreach ($roleName in $roleNames) {
|
||||
# Fetch User Account Administrator role instance
|
||||
$role = Get-AzureADDirectoryRole | Where-Object { $_.displayName -eq $roleName }
|
||||
|
||||
# If role instance does not exist, instantiate it based on the role template
|
||||
if (!($role)) {
|
||||
# Instantiate an instance of the role template
|
||||
$roleTemplate = Get-AzureADDirectoryRoleTemplate | Where-Object { $_.displayName -eq $roleName }
|
||||
Enable-AzureADDirectoryRole -RoleTemplateId $roleTemplate.ObjectId
|
||||
|
||||
# Fetch User Account Administrator role instance again
|
||||
$role = Get-AzureADDirectoryRole | Where-Object { $_.displayName -eq $roleName }
|
||||
}
|
||||
|
||||
# Get existing users with the role assigned
|
||||
$existingRoleUsers = (Get-AzureADDirectoryRoleMember -ObjectId $role.ObjectId).UserPrincipalName
|
||||
|
||||
# Assign role to new user if not already in the list
|
||||
if ($roleMember.UserPrincipalName -notin $existingRoleUsers) {
|
||||
Add-AzureADDirectoryRoleMember -ObjectId $role.ObjectId -RefObjectId $roleMember.ObjectId -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Uncomment to fetch role membership for each role to confirm
|
||||
#foreach ($roleName in $roleNames) {
|
||||
# Write-Output -InputObject ('Members for role: ' + $roleName)
|
||||
# Get-AzureADDirectoryRoleMember -ObjectId $role.ObjectId | Get-AzureADUser | Where-Object {$_.UserPrincipalName -in $roleUsers} | Format-List -Property DisplayName,UserPrincipalName
|
||||
#}
|
||||
@@ -0,0 +1,29 @@
|
||||
# Script to bulk disable guest accounts in Azure AD, either all or for a specific domain
|
||||
#
|
||||
|
||||
# Are we disabling for a specific guest domain? Leave blank for all guests.
|
||||
$guestDomain = ''
|
||||
|
||||
# Install the AzureAD module, uncomment if required
|
||||
#Install-Module -Name AzureAD
|
||||
|
||||
# Import the AzureAD module and connect to Azure AD
|
||||
Import-Module -Name AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Get a list of all guests from Azure AD either matching the domain or all guests
|
||||
if ($guestDomain -ne '') {
|
||||
$guestAccounts = Get-AzureADUser -All $true | Where-Object { $_.AccountEnabled -eq $true -and $_.UserType -eq 'Guest' -and $_.Mail -like ('*' + $guestDomain) }
|
||||
}
|
||||
else {
|
||||
$guestAccounts = Get-AzureADUser -All $true | Where-Object { $_.AccountEnabled -eq $true -and $_.UserType -eq 'Guest' }
|
||||
}
|
||||
|
||||
# Disable the guest accounts
|
||||
try {
|
||||
$guestAccounts | Set-AzureADUser -AccountEnabled $false -ErrorAction Stop
|
||||
Write-Output -InputObject ('The specified guest accounts have been disabled.')
|
||||
}
|
||||
catch {
|
||||
Write-Output -InputObject ('Failed - The specified guest accounts have not been disabled.')
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# Script to bulk enable guest accounts in Azure AD, either all or for a specific domain
|
||||
#
|
||||
|
||||
# Are we disabling for a specific guest domain? Leave blank for all guests.
|
||||
$guestDomain = ''
|
||||
|
||||
# Install the AzureAD module, uncomment if required
|
||||
#Install-Module -Name AzureAD
|
||||
|
||||
# Import the AzureAD module and connect to Azure AD
|
||||
Import-Module -Name AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Get a list of all guests from Azure AD either matching the domain or all guests
|
||||
if ($guestDomain -ne '') {
|
||||
$guestAccounts = Get-AzureADUser -All $true | Where-Object { $_.AccountEnabled -eq $false -and $_.UserType -eq 'Guest' -and $_.Mail -like ('*' + $guestDomain) }
|
||||
}
|
||||
else {
|
||||
$guestAccounts = Get-AzureADUser -All $true | Where-Object { $_.AccountEnabled -eq $false -and $_.UserType -eq 'Guest' }
|
||||
}
|
||||
|
||||
# Enable the guest accounts
|
||||
$guestAccounts | Set-AzureADUser -AccountEnabled $true
|
||||
Write-Output -InputObject ('The specified guest accounts have been disabled.')
|
||||
@@ -0,0 +1,21 @@
|
||||
# Find all guests with unaccepted invites over a specific time period and remove them
|
||||
#
|
||||
|
||||
# How many days are we allowing for invites to be accepted? (This can be 0 for all)
|
||||
$cutOffDays = 30
|
||||
|
||||
# Install the AzureAD module, uncomment if required
|
||||
#Install-Module -Name AzureAD
|
||||
|
||||
# Import the AzureAD module and connect to Azure AD
|
||||
Import-Module -Name AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Get the cut off date
|
||||
$cutOffDate = (Get-Date).AddDays(-$cutOffDays)
|
||||
|
||||
# Get a list of all guests with unaccepted invites older than the specificed timeframe
|
||||
$unacceptedGuests = Get-AzureADUser -All $true | Where-Object { $_.UserType -eq 'Guest' -and $_.UserState -eq 'PendingAcceptance' -and $_.RefreshTokensValidFromDateTime -lt $cutOffDate }
|
||||
|
||||
# Remove the guest accounts
|
||||
$unacceptedGuests | Remove-AzureADUser
|
||||
@@ -0,0 +1,44 @@
|
||||
# Bulk remove licences to a list of users.
|
||||
#
|
||||
# List of available SKUs can be obtained with (Get-AzureADSubscribedSku).SkuPartNumber
|
||||
#
|
||||
|
||||
# Where is the list of user UPN's?
|
||||
$userListPath = 'C:\Temp\UserList.txt'
|
||||
|
||||
# What licences are we removing?
|
||||
$licencesToRemove = @('ENTERPRISEPACK','ATP_ENTERPRISE','EMSPREMIUM')
|
||||
|
||||
# Import AzureAD module and connect
|
||||
Import-Module AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Import list of users from file
|
||||
$userList = Get-Content -Path $userListPath | Sort-Object
|
||||
|
||||
# Create a licenses object
|
||||
$licenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses
|
||||
|
||||
# Get SkuIDs for licence(s) to be removed
|
||||
$licenses.RemoveLicenses = (Get-AzureADSubscribedSku | Where-Object {$_.SkuPartNumber -in $licencesToRemove}).SkuId
|
||||
|
||||
# Remove the licenses
|
||||
foreach ($username in $userList) {
|
||||
try {
|
||||
$user = Get-AzureADUser -ObjectId $username -ErrorAction Stop
|
||||
if ($user.AccountEnabled -eq $true) {
|
||||
Set-AzureADUserLicense -ObjectId $user.UserPrincipalName -AssignedLicenses $licenses
|
||||
Write-Output -InputObject ('Licence(s) removed from user account ' + $user.UserPrincipalName + '.')
|
||||
}
|
||||
else {
|
||||
Write-Output -InputObject ('User account ' + $user.UserPrincipalName + ' is disabled.')
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Output -InputObject ('There was a problem updating licences for user account ' + $user.UserPrincipalName + '.')
|
||||
Write-Output -InputObject $Error[0]
|
||||
}
|
||||
}
|
||||
|
||||
# Disconnect from AzureAD
|
||||
Disconnect-AzureAD
|
||||
@@ -0,0 +1,59 @@
|
||||
# Bulk replace licences to a list of users.
|
||||
#
|
||||
# List of available SKUs can be obtained with (Get-AzureADSubscribedSku).SkuPartNumber
|
||||
#
|
||||
|
||||
# Where is the list of user UPN's?
|
||||
$userListPath = 'C:\Temp\UserList.txt'
|
||||
|
||||
# What licences are we adding?
|
||||
$licencesToAdd = @('EMSPREMIUM')
|
||||
|
||||
# What licences are we removing?
|
||||
$licencesToRemove = @('EMS','AAD_PREMIUM_P2')
|
||||
|
||||
# Import AzureAD module and connect
|
||||
Import-Module AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Import list of users from file
|
||||
$userList = Get-Content -Path $userListPath | Sort-Object
|
||||
|
||||
$userList = @('OAndrewsAdmin@sis.tv')
|
||||
|
||||
# Get all available licence skus
|
||||
$newSkuIDs = (Get-AzureADSubscribedSku | Where-Object {$_.SkuPartNumber -in $licencesToAdd}).SkuId
|
||||
|
||||
# Create a licenses object
|
||||
$licenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses
|
||||
|
||||
# Add the licences to add to the licences object
|
||||
foreach ($newSkuID in $newSkuIDs) {
|
||||
$newLicense = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense
|
||||
$newLicense.SkuId = $newSkuID
|
||||
$licenses.AddLicenses += $newLicense
|
||||
}
|
||||
|
||||
# Add the licences we want to remove to the $licenses object
|
||||
$licenses.RemoveLicenses = (Get-AzureADSubscribedSku | Where-Object {$_.SkuPartNumber -in $licencesToRemove}).SkuID
|
||||
|
||||
# Replace the licenses
|
||||
foreach ($username in $userList) {
|
||||
try {
|
||||
$user = Get-AzureADUser -ObjectId $username -ErrorAction Stop
|
||||
if ($user.AccountEnabled -eq $true) {
|
||||
Set-AzureADUserLicense -ObjectId $user.UserPrincipalName -AssignedLicenses $licenses
|
||||
Write-Output -InputObject ('Licences updated for user account ' + $user.UserPrincipalName + '.')
|
||||
}
|
||||
else {
|
||||
Write-Output -InputObject ('User account ' + $user.UserPrincipalName + ' is disabled.')
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Output -InputObject ('There was a problem updating licences for user account ' + $user.UserPrincipalName + '.')
|
||||
Write-Output -InputObject $Error[0]
|
||||
}
|
||||
}
|
||||
|
||||
# Disconnect from AzureAD
|
||||
Disconnect-AzureAD
|
||||
@@ -0,0 +1,14 @@
|
||||
# Update Online User UPN - when AD sync doesn't do it.
|
||||
|
||||
# Import the Azure AD module and connect
|
||||
Import-Module AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Whose UPN are we changing?
|
||||
$oldUPN = Read-Host -Prompt 'Enter user''s old UPN in the format username@domain'
|
||||
|
||||
# What are we changing it to?
|
||||
$newUPN = Read-Host -Prompt 'Enter user''s new UPN in the format username@domain'
|
||||
|
||||
# Update the UPN in AzureAD
|
||||
Set-AzureADUser -ObjectId $oldUPN -UserPrincipalName $newUPN
|
||||
@@ -0,0 +1,10 @@
|
||||
# Import the Azure AD module and connect
|
||||
Import-Module AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Whose ID are we getting?
|
||||
$userUPN = Read-Host -Prompt 'Enter user''s UPN in the format username@domain'
|
||||
|
||||
# Convert 365 ImmutableID to AD GUID
|
||||
$immutableID = (Get-AzureADUser -ObjectId $userUPN).ImmutableID
|
||||
[GUID][System.Convert]::FromBase64String($immutableID)
|
||||
@@ -0,0 +1,29 @@
|
||||
# Retrieve licences for all users and export to CSV.
|
||||
#
|
||||
|
||||
# Import AzureAD module and connect
|
||||
Import-Module AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Get all available licence details
|
||||
$allSkus = Get-AzureADSubscribedSku
|
||||
|
||||
# Import list of users from file
|
||||
$users = Get-AzureADUser -All $true
|
||||
|
||||
# Get Licences for each user and find out what they are from the list
|
||||
$allUserLicences = @()
|
||||
foreach ($user in $users) {
|
||||
$assignedLicences = @()
|
||||
foreach ($license in $user.AssignedLicenses.SkuID) {
|
||||
$assignedLicences += ($allSkus | Where-Object { $_.SkuID -eq $license }).SkuPartNumber
|
||||
}
|
||||
$userLicences = [PSCustomObject]@{
|
||||
'UserName' = $user.UserPrincipalName
|
||||
'AssignedLicences' = (($assignedLicences | Sort-Object) -join ';')
|
||||
}
|
||||
$allUserLicences += $userLicences
|
||||
}
|
||||
|
||||
# Export list to CSV file
|
||||
$allUserLicences | Export-Csv -Path 'C:\Temp\AllUserLicences.csv' -NoTypeInformation
|
||||
@@ -0,0 +1,38 @@
|
||||
# Retrieve licences for a list of users and export them to a CSV file.
|
||||
#
|
||||
|
||||
# Where is the list of user UPN's?
|
||||
$userListPath = 'C:\Temp\UserList.txt'
|
||||
|
||||
# Import AzureAD module and connect
|
||||
Import-Module AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Get all available licence details
|
||||
$allSkus = Get-AzureADSubscribedSku
|
||||
|
||||
# Import list of users from file
|
||||
$users = Get-Content -Path $userListPath | Sort-Object
|
||||
|
||||
# Get Licences for user and find out what they are from the list
|
||||
$allUserLicences = @()
|
||||
foreach ($user in $users) {
|
||||
$assignedLicences = @()
|
||||
try {
|
||||
$userDetails = Get-AzureADUser -ObjectId $user -ErrorAction Stop
|
||||
foreach ($license in $userDetails.AssignedLicenses.SkuID) {
|
||||
$assignedLicences += ($allSkus | Where-Object { $_.SkuID -eq $license }).SkuPartNumber
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$assignedLicences = 'User not found.'
|
||||
}
|
||||
$userLicences = [PSCustomObject]@{
|
||||
'UserName' = $user
|
||||
'AssignedLicences' = (($assignedLicences | Sort-Object) -join ';')
|
||||
}
|
||||
$allUserLicences += $userLicences
|
||||
}
|
||||
|
||||
# Export list to CSV file
|
||||
$allUserLicences | Export-Csv -Path 'C:\Temp\UserLicences.csv' -NoTypeInformation
|
||||
@@ -0,0 +1,84 @@
|
||||
# Some example scripts for finding users with specific plans assigned
|
||||
#
|
||||
# A full list of subscription and plan ID's is available from:
|
||||
# https://docs.microsoft.com/en-us/azure/active-directory/users-groups-roles/licensing-service-plan-reference
|
||||
#
|
||||
# Here I'm using the following plan IDs.
|
||||
#
|
||||
# OFFICESUBSCRIPTION (43de0ff5-c92c-492b-9116-175376d08c38)
|
||||
# PROJECT_CLIENT_SUBSCRIPTION (fafd7243-e5c1-4a3a-9e40-495efcb1d3c3)
|
||||
# VISIO_CLIENT_SUBSCRIPTION (663a804f-1c30-4ff0-9915-9db84f0d1cea)
|
||||
#
|
||||
|
||||
# Plan ID's to check for
|
||||
$planID1 = '43de0ff5-c92c-492b-9116-175376d08c38'
|
||||
$planID2 = 'fafd7243-e5c1-4a3a-9e40-495efcb1d3c3'
|
||||
$planID3 = '663a804f-1c30-4ff0-9915-9db84f0d1cea'
|
||||
|
||||
# Import the AzureAD module and connect
|
||||
Import-Module AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Get all users from AzureAD
|
||||
$allUsers = Get-AzureADUser -All $true
|
||||
|
||||
# Create variables to put the users in to
|
||||
$planID1Users = @()
|
||||
$planID2Users = @()
|
||||
$planID3Users = @()
|
||||
|
||||
# Check through the users and check what plans are assigned and enabled
|
||||
foreach ($user in $allUsers) {
|
||||
foreach ($assignedPlan in $user.AssignedPlans) {
|
||||
# Find all users of plan 1 and add to the related variable
|
||||
if ($assignedPlan.ServicePlanId -eq $planID1 -and $assignedPlan.CapabilityStatus -eq 'Enabled') {
|
||||
$planID1Users += $user
|
||||
}
|
||||
# Find all users of plan 2 and add to the related variable
|
||||
if ($assignedPlan.ServicePlanId -eq $planID2 -and $assignedPlan.CapabilityStatus -eq 'Enabled') {
|
||||
$planID2Users += $user
|
||||
}
|
||||
# Find all users of plan 3 and add to the related variable
|
||||
if ($assignedPlan.ServicePlanId -eq $planID3 -and $assignedPlan.CapabilityStatus -eq 'Enabled') {
|
||||
$planID3Users += $user
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Create variables to put the users in to
|
||||
$plan1OnlyUsers = @()
|
||||
$planID1and2Users = @()
|
||||
$planID1and3Users = @()
|
||||
$planID12and3Users = @()
|
||||
|
||||
# Using plan 1 as the master list, check which other licences are assigned
|
||||
foreach ($planID1User in $planID1Users) {
|
||||
# Find users who are only in the plan 1 list
|
||||
if ($planID1User -notin $planID2Users -and $planID1User -notin $planID3Users) {
|
||||
$plan1OnlyUsers += $planID1User
|
||||
}
|
||||
# Find users who are the plan 1 and plan 2 list
|
||||
if ($planID1User -in $planID2Users) {
|
||||
$planID1and2Users += $planID1User
|
||||
}
|
||||
# Find users who are in the plan 1 and plan 3 list
|
||||
if ($planID1User -in $planID3Users) {
|
||||
$planID1and3Users += $planID1User
|
||||
}
|
||||
# Find users who are in all three lists
|
||||
if ($planID1User -in $planID2Users -and $planID1User -in $planID3Users) {
|
||||
$planID12and3Users += $planID1User
|
||||
}
|
||||
}
|
||||
|
||||
# How many people in each list?
|
||||
$plan1OnlyUsers.Count
|
||||
$planID1and2Users.Count
|
||||
$planID1and3Users.Count
|
||||
$planID12and3Users.Count
|
||||
|
||||
# Who are those people?
|
||||
$plan1OnlyUsers
|
||||
$planID1and2Users
|
||||
$planID1and3Users
|
||||
$planID12and3Users
|
||||
@@ -0,0 +1,36 @@
|
||||
# Script to invite a list of guest users to AzureAD and add them to a group
|
||||
#
|
||||
# Useful for bulk adding guests to a SharePoint or Teams group
|
||||
#
|
||||
# Uses a CSV file containing columns for FirstName,LastName,DisplayName,ExternalEmailAddress
|
||||
#
|
||||
|
||||
# Where is our list of people?
|
||||
$contactsFile = 'C:\Temp\ExternalContacts.csv'
|
||||
|
||||
# What group are we added them to?
|
||||
$groupName = 'Test Group'
|
||||
|
||||
# Import the AzureAD module and connect
|
||||
Import-Module AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Import the list of people
|
||||
$contactsList = Import-Csv -Path $contactsFile
|
||||
|
||||
# Find the group ID for our group
|
||||
$groupID = (Get-AzureADGroup -All $true | Where-Object {$_.DisplayName -eq $groupName}).ObjectId
|
||||
|
||||
# Run through the list sending the guest invite and adding them to the group, unless their email address is already used somewhere
|
||||
foreach ($externalUser in $contactsList) {
|
||||
$getExisting = Get-AzureADUser -SearchString $externalUser.ExternalEmailAddress
|
||||
|
||||
if ($getExisting.Count -eq 0) {
|
||||
$newUser = New-AzureADMSInvitation -InvitedUserDisplayName $externalUser.DisplayName -InvitedUserEmailAddress $externalUser.ExternalEmailAddress -SendInvitationMessage $true -InviteRedirectUrl "https://myapps.microsoft.com"
|
||||
Add-AzureADGroupMember -ObjectId $groupID -RefObjectId $newUser.InvitedUser.Id
|
||||
Write-Output -InputObject ('Guest ' + $externalUser.ExternalEmailAddress + ' created and added to group.')
|
||||
}
|
||||
else {
|
||||
Write-Output -InputObject ('Object already exists with email address ' + $externalUser.ExternalEmailAddress + '.')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
# Remove all licences from a list of users
|
||||
#
|
||||
# Removing licences with this module doesn't work in the way that Microsoft's documentation states.
|
||||
# I'm assuming this is a bug, so the code below works at time of creation but may stop working in the future.
|
||||
#
|
||||
|
||||
# Where is the list of user UPN's?
|
||||
$userListPath = 'C:\Temp\UserList.txt'
|
||||
|
||||
# Import AzureAD module and connect
|
||||
Import-Module AzureAD
|
||||
Connect-AzureAD
|
||||
|
||||
# Import list of users from file
|
||||
$userList = Get-Content -Path $userListPath | Sort-Object
|
||||
|
||||
# Remove all the licences
|
||||
foreach ($username in $userList) {
|
||||
try {
|
||||
$user = Get-AzureADUser -ObjectId $username -ErrorAction Stop
|
||||
if ($user.AccountEnabled -eq $true) {
|
||||
if(($user.AssignedLicenses.SkuId).Count -ge 1) {
|
||||
$licenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses
|
||||
$licenses.RemoveLicenses = (Get-AzureADSubscribedSku | Where-Object {$_.SkuId -in $user.AssignedLicenses.SkuId}).SkuId
|
||||
Set-AzureADUserLicense -ObjectId $user.UserPrincipalName -AssignedLicenses $licenses
|
||||
Write-Output -InputObject ('All licences removed from user account ' + $username + '.')
|
||||
}
|
||||
else {
|
||||
Write-Output -InputObject ('User account ' + $username + ' has no licences assigned.')
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Output -InputObject ('User account ' + $username + ' is disabled.')
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Output -InputObject ('User account ' + $username + ' does not exist.')
|
||||
}
|
||||
}
|
||||
|
||||
# Disconnect from AzureAD
|
||||
Disconnect-AzureAD
|
||||
@@ -0,0 +1,63 @@
|
||||
# Script to get details for a list of mailboxes and save that out to a CSV file
|
||||
#
|
||||
|
||||
# File containing the list of mailboxes
|
||||
$inputFile = 'C:\Temp\MailboxList.txt'
|
||||
|
||||
# File to save the results to
|
||||
$outputFile = 'C:\Temp\SharedMailboxes.csv'
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
$credentials = Get-Credential -Message 'Enter your Exchange Online administrator credentials'
|
||||
$connectionParams = @{
|
||||
'ConfigurationName' = 'Microsoft.Exchange';
|
||||
'ConnectionUri' = 'https://outlook.office365.com/powershell-liveid/';
|
||||
'Credential' = $credentials;
|
||||
'Authentication' = 'Basic';
|
||||
'AllowRedirection' = $true
|
||||
}
|
||||
$exchangeSession = New-PSSession @connectionParams
|
||||
Import-PSSession -Session $exchangeSession
|
||||
|
||||
# Check output folder exists and create it if it doesn't
|
||||
$outputPath = (Split-Path -Path $outputFile)
|
||||
if (!(Test-Path -Path $outputPath)) {New-Item -Path $outputFolder -ItemType Directory}
|
||||
|
||||
# If output file already exists, delete it.
|
||||
if (Test-Path -Path $outputFile) {Remove-Item -Path $outputFile}
|
||||
|
||||
# Get the list of mailboxes from the file
|
||||
$mailboxes = Get-Content -Path $inputFile
|
||||
|
||||
# Initialise the results table
|
||||
$mailboxesTable = @()
|
||||
|
||||
# Iterate through the mailboxes from the file and show a progress bar as we go.
|
||||
foreach ($mailbox in $mailboxes) {
|
||||
Write-Progress -Activity 'Checking..' -status $mailbox -percentComplete ($mailboxes.IndexOf($mailbox) / $mailboxes.Count * 100)
|
||||
|
||||
# Get the statistics for the mailbox.
|
||||
$mailboxStats = ''
|
||||
$mailboxStats = Get-MailboxStatistics -Identity $mailbox -ErrorAction SilentlyContinue -
|
||||
|
||||
# If mailboxStats is blank then mailbox doesn't exist, so that entry can be skipped. For all others get the mailbox permissions and build the output table.
|
||||
if ($mailboxStats -ne $null) {
|
||||
# Get permit permissions for users where the username has an @ in it, this filters out all the system permissions.
|
||||
$usersWithAccess = (Get-MailboxPermission -Identity $mailbox | Where-Object -Property {($_.User -like '*@*') -and ($_.Deny -ne 'False')}).User -join '; '
|
||||
|
||||
$tableRow = New-Object System.Object
|
||||
$tableRow | Add-Member -MemberType NoteProperty -Name 'MailboxUPN' -Value $mailbox
|
||||
$tableRow | Add-Member -MemberType NoteProperty -Name 'MailboxType' -Value $mailboxStats.MailboxTypeDetail
|
||||
$tableRow | Add-Member -MemberType NoteProperty -Name 'ItemCount' -Value $mailboxStats.ItemCount
|
||||
$tableRow | Add-Member -MemberType NoteProperty -Name 'TotalItemSize' -Value $mailboxStats.TotalItemSize
|
||||
$tableRow | Add-Member -MemberType NoteProperty -Name 'LastLogonTime' -Value $mailboxStats.LastLogonTime
|
||||
$tableRow | Add-Member -MemberType NoteProperty -Name 'UsersWithAccess' -Value $usersWithAccess
|
||||
$mailboxesTable += $tableRow
|
||||
}
|
||||
}
|
||||
|
||||
# Output the final table of results to a file.
|
||||
$mailboxesTable | Export-Csv -Path $outputFile -NoTypeInformation
|
||||
|
||||
# End the Exchange Online session
|
||||
Remove-PSSession -Session $exchangeSession
|
||||
@@ -0,0 +1,20 @@
|
||||
# Find mailboxes where UPN domain doesn't match email domain
|
||||
#
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
$credentials = Get-Credential -Message 'Enter your Exchange Online administrator credentials'
|
||||
$connectionParams = @{
|
||||
'ConfigurationName' = 'Microsoft.Exchange';
|
||||
'ConnectionUri' = 'https://outlook.office365.com/powershell-liveid/';
|
||||
'Credential' = $credentials;
|
||||
'Authentication' = 'Basic';
|
||||
'AllowRedirection' = $true
|
||||
}
|
||||
$exchangeSession = New-PSSession @connectionParams
|
||||
Import-PSSession -Session $exchangeSession
|
||||
|
||||
# Get list of mailboxes with a different mail domain to UPN domain
|
||||
Get-Mailbox -ResultSize Unlimited | Where-Object {$_.UserPrincipalName.Split('@')[1] -ne $_.PrimarySmtpAddress.Split('@')[1]} | Format-Table Name,UserPrincipalName,PrimarySmtpAddress,RecipientTypeDetails
|
||||
|
||||
# Disconnect from Exchange Online
|
||||
Remove-PSSession $exchangeSession
|
||||
@@ -0,0 +1,38 @@
|
||||
# Script to get all client forwarding rules, smtp forwarding rules and delegates on mailboxes
|
||||
#
|
||||
# This builds on top of a script from https://github.com/OfficeDev/O365-InvestigationTooling
|
||||
#
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
$credentials = Get-Credential -Message 'Enter your Exchange Online administrator credentials'
|
||||
$connectionParams = @{
|
||||
'ConfigurationName' = 'Microsoft.Exchange';
|
||||
'ConnectionUri' = 'https://outlook.office365.com/powershell-liveid/';
|
||||
'Credential' = $credentials;
|
||||
'Authentication' = 'Basic';
|
||||
'AllowRedirection' = $true
|
||||
}
|
||||
$exchangeSession = New-PSSession @connectionParams
|
||||
Import-PSSession -Session $exchangeSession
|
||||
|
||||
$allUsers = @()
|
||||
$allUsers = Get-Mailbox -ResultSize Unlimited | Select-Object DisplayName,UserPrincipalName,ForwardingAddress,ForwardingSMTPAddress,DeliverToMailboxandForward
|
||||
|
||||
$userInboxRules = @()
|
||||
$userDelegates = @()
|
||||
|
||||
foreach ($user in $allUsers) {
|
||||
Write-Progress -Activity "Checking inbox rules for..." -status $user.UserPrincipalName -percentComplete ($allUsers.IndexOf($user) / $allUsers.Count * 100)
|
||||
$userInboxRules += Get-InboxRule -Mailbox $user.UserPrincipalName | `
|
||||
Select-Object MailboxOwnerId,Name,Description,Enabled,Priority,ForwardTo,ForwardAsAttachmentTo,RedirectTo,DeleteMessage | `
|
||||
Where-Object {($_.ForwardTo -ne $null) -or ($_.ForwardAsAttachmentTo -ne $null) -or ($_.RedirectsTo -ne $null)}
|
||||
$userDelegates += Get-MailboxPermission -Identity $user.UserPrincipalName | Where-Object {($_.IsInherited -ne "True") -and ($_.User -notlike "*SELF*")}
|
||||
}
|
||||
|
||||
$smtpForwarding = $allUsers | Select-Object DisplayName,ForwardingAddress,ForwardingSMTPAddress,DeliverToMailboxandForward | Where-Object {$_.ForwardingSMTPAddress -ne $null}
|
||||
|
||||
$userInboxRules | Export-Csv MailForwardingRulesToExternalDomains.csv -NoTypeInformation
|
||||
$smtpForwarding | Export-Csv Mailboxsmtpforwarding.csv -NoTypeInformation
|
||||
$userDelegates | Export-Csv MailboxDelegatePermissions.csv -NoTypeInformation
|
||||
|
||||
Remove-PSSession -Session $exchangeSession
|
||||
@@ -0,0 +1,41 @@
|
||||
# Script to grant access rights on mailboxes
|
||||
#
|
||||
|
||||
# Mailboxes to grant rights on
|
||||
$grantRightsOnMailboxes = @('','')
|
||||
|
||||
# Users to grant rights to
|
||||
$grantRightsToUsers = @('','')
|
||||
|
||||
# Rights to grant
|
||||
$accessRights = 'Editor'
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
$credentials = Get-Credential -Message 'Enter your Exchange Online administrator credentials'
|
||||
$connectionParams = @{
|
||||
'ConfigurationName' = 'Microsoft.Exchange';
|
||||
'ConnectionUri' = 'https://outlook.office365.com/powershell-liveid/';
|
||||
'Credential' = $credentials;
|
||||
'Authentication' = 'Basic';
|
||||
'AllowRedirection' = $true
|
||||
}
|
||||
$exchangeSession = New-PSSession @connectionParams
|
||||
Import-PSSession -Session $exchangeSession
|
||||
|
||||
# Apply the permissions
|
||||
foreach ($grantRightsToUser in $grantRightsToUsers ) {
|
||||
foreach ($grantRightsOnMailbox in $grantRightsOnMailboxes) {
|
||||
$calendarIdentity = $grantRightsOnMailbox + ':\Calendar'
|
||||
$existingPermissions = Get-MailboxFolderPermission -Identity $calendarIdentity -User $grantRightsToUser -ErrorAction SilentlyContinue
|
||||
if (!($existingPermissions)) {
|
||||
Add-MailboxFolderPermission -Identity $calendarIdentity -User $grantRightsToUser -AccessRights $accessRights
|
||||
}
|
||||
else {
|
||||
Set-MailboxFolderPermission -Identity $calendarIdentity -User $grantRightsToUser -AccessRights $accessRights
|
||||
}
|
||||
Set-Mailbox -Identity $upn –GrantSendOnBehalfTo @{add=$editor}
|
||||
}
|
||||
}
|
||||
|
||||
# End the PowerShell session
|
||||
Remove-PSSession -Session $exchangeSession
|
||||
@@ -0,0 +1,45 @@
|
||||
# Enable mailbox auditing and disable PowerShell remoting on individual mailboxes
|
||||
#
|
||||
# Working on this as a one stop for hardening Exchange Online accounts
|
||||
#
|
||||
|
||||
# UPN of New User
|
||||
$newUPN = ''
|
||||
|
||||
# Is the user an administrator?
|
||||
$isAnAdmin = $false
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
$credentials = Get-Credential -Message 'Enter your Exchange Online administrator credentials'
|
||||
$connectionParams = @{
|
||||
'ConfigurationName' = 'Microsoft.Exchange';
|
||||
'ConnectionUri' = 'https://outlook.office365.com/powershell-liveid/';
|
||||
'Credential' = $credentials;
|
||||
'Authentication' = 'Basic';
|
||||
'AllowRedirection' = $true
|
||||
}
|
||||
$exchangeSession = New-PSSession @connectionParams
|
||||
Import-PSSession -Session $exchangeSession
|
||||
|
||||
# Set Auditing parameters
|
||||
$params = @{
|
||||
'AuditEnabled' = $true
|
||||
'AuditLogAgeLimit' = '180'
|
||||
'AuditAdmin' = @('Update','MoveToDeletedItems','SoftDelete','HardDelete','SendAs','SendOnBehalf','Create','UpdateFolderPermission')
|
||||
'AuditDelegate' = @('Update','SoftDelete','HardDelete','SendAs','Create','UpdateFolderPermissions','MoveToDeletedItems','SendOnBehalf')
|
||||
'AuditOwner' = @('UpdateFolderPermission','MailboxLogin','Create','SoftDelete','HardDelete','Update','MoveToDeletedItems')
|
||||
}
|
||||
|
||||
# Enable Auditing
|
||||
Get-Mailbox -Identity $newUPN | Set-Mailbox @params
|
||||
|
||||
# Disable PowerShell Remoting for non-Admin staff
|
||||
if ($isAnAdmin) {
|
||||
Set-User -Identity $newUPN -RemotePowerShellEnabled $true
|
||||
}
|
||||
else {
|
||||
Set-User -Identity $newUPN -RemotePowerShellEnabled $false
|
||||
}
|
||||
|
||||
# Disconnect from Exchange Online
|
||||
Remove-PSSession $exchangeSession
|
||||
@@ -0,0 +1,111 @@
|
||||
# Script to bulk remove email proxy addresses from Exchange users in a synced environment using an on-prem Exchange management server
|
||||
#
|
||||
|
||||
# What is the FQDN of the on-prem Exchange server?
|
||||
$exchangeServerFQDN = ''
|
||||
|
||||
# Which domains are we removing?
|
||||
$domainsToRemove = @('','')
|
||||
|
||||
# Create Exchange connection Uri from FQDN
|
||||
$exchangeConnectionUri = 'http://' + $exchangeServerFQDN +'/PowerShell/'
|
||||
|
||||
# Establish a session to Exchange
|
||||
$userCredential = Get-Credential
|
||||
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $exchangeConnectionUri -Authentication Kerberos -Credential $userCredential
|
||||
Import-PSSession $session -DisableNameChecking
|
||||
|
||||
### Check if address policies are using this domain ###
|
||||
|
||||
# Initialise a hastable to store our results in
|
||||
$addressPolicies = @()
|
||||
|
||||
# Get all address policies from Exchange
|
||||
$allAddressPolicies = Get-EmailAddressPolicy
|
||||
|
||||
# Run through the domains checking if the domain to be removed is in the address policies
|
||||
foreach ($domainToRemove in $domainsToRemove) {
|
||||
$emailAddressTemplate = 'SMTP:@' + $domainToRemove
|
||||
$addressPolicies += $allAddressPolicies | Where-Object {$_.EnabledEmailAddressTemplates -contains $emailAddressTemplate}
|
||||
}
|
||||
|
||||
# If domain found in address policies then list them and ask if we want to contiue removing the proxy domain
|
||||
if ($addressPolicies.Count -gt 0) {
|
||||
Write-Output -InputObject ('The following address policies are using the domain to be removed:')
|
||||
$addressPolicies | Format-Table
|
||||
$continue = ''
|
||||
while ($continue -notmatch '[YyNn]') {
|
||||
$continue = Read-Host -Prompt 'Do you want to continue running the script? (Y/N)'
|
||||
}
|
||||
if ($continue -match '[Nn]') {
|
||||
Write-Output -InputObject ('Terminating script.')
|
||||
break
|
||||
}
|
||||
else {
|
||||
Write-Output -InputObject ('Continuing with script.')
|
||||
}
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
### Remove the domain from mailboxes ###
|
||||
|
||||
# Get All Mailboxes
|
||||
$allMailboxes = Get-RemoteMailbox -ResultSize Unlimited | Sort-Object -Property alias
|
||||
|
||||
# Remove alias from each mailbox
|
||||
foreach ($mailbox in $allMailboxes) {
|
||||
$redundantAddresses = @()
|
||||
foreach ($domainToRemove in $domainsToRemove) {
|
||||
$redundantAddresses += (($mailbox.EmailAddresses -split ',' | Where-Object {$_ -match $domainToRemove}) -replace 'smtp:','')
|
||||
}
|
||||
if ($redundantAddresses.Count -gt 0) {
|
||||
Write-Output -InputObject ('Removing addresses ' + $redundantAddresses + ' from maibox ' + $mailbox.Name)
|
||||
Set-RemoteMailbox -Identity $mailbox.Identity -EmailAddresses @{remove=$redundantAddresses} -Confirm:$false
|
||||
}
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
### Remove the domain from contacts ###
|
||||
|
||||
# Get all the contacts
|
||||
$allContacts = Get-MailContact -ResultSize Unlimited | Sort-Object -Property alias
|
||||
|
||||
# Remove alias from each contact
|
||||
foreach ($contact in $allContacts) {
|
||||
$redundantAddresses = @()
|
||||
foreach ($domainToRemove in $domainsToRemove) {
|
||||
$redundantAddresses += (($contact.EmailAddresses -split ',' | Where-Object {$_ -like ('*' + $domainToRemove + '*')}) -replace 'smtp:','')
|
||||
}
|
||||
if ($redundantAddresses.Count -gt 0) {
|
||||
Write-Output -InputObject ('Removing addresses ' + $redundantAddresses + ' from contact ' + $contact.Name)
|
||||
Set-MailContact -Identity $contact.Identity -EmailAddresses @{remove=$redundantAddresses} -Confirm:$false -ForceUpgrade:$true
|
||||
}
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
### Remove the domain from groups ###
|
||||
|
||||
# Get all the groups (this includes email enabled security groups)
|
||||
$allGroups = Get-DistributionGroup -ResultSize Unlimited | Sort-Object -Property alias
|
||||
|
||||
# Remove alias from each group
|
||||
foreach ($group in $allGroups) {
|
||||
$redundantAddresses = @()
|
||||
foreach ($domainToRemove in $domainsToRemove) {
|
||||
$redundantAddresses += (($group.EmailAddresses -split ',' | Where-Object {$_ -like ('*' + $domainToRemove + '*')}) -replace 'smtp:','')
|
||||
}
|
||||
if ($redundantAddresses.Count -gt 0) {
|
||||
Write-Output -InputObject ('Removing addresses ' + $redundantAddresses + ' from group ' + $group.Name)
|
||||
Set-DistributionGroup -Identity $group.Identity -EmailAddresses @{remove=$redundantAddresses} -Confirm:$false
|
||||
}
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
### Public folders don't feature here because in this scenario they're cloud only ###
|
||||
|
||||
# End the Exchange Session
|
||||
Remove-PSSession -Session $session
|
||||
@@ -0,0 +1,62 @@
|
||||
# Find mailboxes for synced accounts, where the mailbox exists in Exchange Online but doesn't exist on-prem as a remote mailbox.
|
||||
#
|
||||
# Like the other stuff in this folder, it's a bit of a niche scenario.
|
||||
# We're looking for mailboxes which were created in on-prem AD and then licenced in the cloud without a remote mailbox being created on the on-prem Exchange server, so that we can remote mail enable them correctly.
|
||||
#
|
||||
# This is a bit complicated as it requires connected to two Exchange environments at once, so uses command prefixes for one of them.
|
||||
#
|
||||
|
||||
# What is the FQDN of the on-prem Exchange server?
|
||||
$exchangeServerFQDN = ''
|
||||
|
||||
# What is your remote routing address? E.g.: @domain.mail.onmicrosoft.com
|
||||
$remoteRoutingSuffix = '@domain.mail.onmicrosoft.com'
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
# Create Exchange on-prem connection Uri from FQDN
|
||||
$exchangeConnectionUri = 'http://' + $exchangeServerFQDN +'/PowerShell/'
|
||||
|
||||
# Establish a session to Exchange on-prem and add the OnPrem prefix to all commands
|
||||
$userCredential = Get-Credential
|
||||
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $exchangeConnectionUri -Authentication Kerberos -Credential $userCredential
|
||||
Import-PSSession $session -DisableNameChecking -Prefix OnPrem
|
||||
|
||||
# Get list of mailboxes from Exchange online for synced users
|
||||
$allOnlineMailboxes = Get-Mailbox -ResultSize Unlimited | Where-Object {$_.IsDirSynced -eq $true -and $_.Name -notlike 'DiscoverySearchMailbox*'}
|
||||
|
||||
# Get list of remote mailboxes from on-prem server
|
||||
$allOnPremMailboxes = Get-OnPremRemoteMailbox -ResultSize Unlimited
|
||||
|
||||
# Compare the two lists and add those missing from the on-prem list to the $syncedMailboxMismatch hashtable
|
||||
$syncedMailboxMismatch = $allOnlineMailboxes | Where-Object {$allOnPremMailboxes.PrimarySmtpAddress -notcontains $_.PrimarySmtpAddress}
|
||||
|
||||
# Find mailboxes where alias and username match
|
||||
$matchedUPNAliases = $syncedMailboxMismatch | Where-Object {$_.Alias -eq $_.UserPrincipalName.Split('@')[0]}
|
||||
|
||||
# Find mailboxes where alias and username don't match
|
||||
$mismatchedUPNAliases = $syncedMailboxMismatch | Where-Object {$_.Alias -ne $_.UserPrincipalName.Split('@')[0]}
|
||||
|
||||
# Fix the mailboxes where username and alias matched.
|
||||
foreach ($mailboxToRemoteEnable in $matchedUPNAliases) {
|
||||
$mailboxUsername = $mailboxToRemoteEnable.UserPrincipalName.Split('@')[0]
|
||||
$mailboxToFix = $mailboxToRemoteEnable.UserPrincipalName
|
||||
$remoteRoutingAddress = $mailboxUsername + $remoteRoutingSuffix
|
||||
Enable-OnPremRemoteMailbox -Identity $mailboxToFix -RemoteRoutingAddress $remoteRoutingAddress
|
||||
}
|
||||
|
||||
# Write out the mailboxes that have been updated
|
||||
Write-Output -InputObject ('The following mailboxes have been remote mail enabled.')
|
||||
$matchedUPNAliases | Select-Object Name,Alias,UserPrincipalName,PrimarySmtpAddress
|
||||
|
||||
# Write out the mailboxes that have been left due to a mismatch between username and alias
|
||||
Write-Output -InputObject ('The following mailboxes have not been changed because they have a mismatch between email alias and username.')
|
||||
$mismatchedUPNAliases | Select-Object Name,Alias,UserPrincipalName,PrimarySmtpAddress
|
||||
|
||||
# End the Exchange Session
|
||||
Remove-PSSession -Session $session
|
||||
@@ -0,0 +1,24 @@
|
||||
# Disable a list of mail users
|
||||
#
|
||||
|
||||
# What is the FQDN of the on-prem Exchange server?
|
||||
$exchangeServerFQDN = ''
|
||||
|
||||
# What accounts are we disabling?
|
||||
$usersToDisable = @('','')
|
||||
|
||||
# Create Exchange connection Uri from FQDN
|
||||
$exchangeConnectionUri = 'http://' + $exchangeServerFQDN +'/PowerShell/'
|
||||
|
||||
# Establish a session to Exchange
|
||||
$userCredential = Get-Credential
|
||||
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $exchangeConnectionUri -Authentication Kerberos -Credential $userCredential
|
||||
Import-PSSession $session -DisableNameChecking -AllowClobber
|
||||
|
||||
# Get list of mailboxes
|
||||
foreach ($userToDisable in $usersToDisable) {
|
||||
Disable-RemoteMailbox -Identity $userToDisable -Confirm:$false
|
||||
}
|
||||
|
||||
# End the Exchange Session
|
||||
Remove-PSSession -Session $session
|
||||
@@ -0,0 +1,28 @@
|
||||
# Find mailboxes using a specific email domain and export list to CSV file
|
||||
#
|
||||
|
||||
# What is the FQDN of the on-prem Exchange server?
|
||||
$exchangeServerFQDN = ''
|
||||
|
||||
# Primary SMTP domain to search for
|
||||
$primarySMTP = ''
|
||||
|
||||
# Where are we saving the output file?
|
||||
$outputFile = 'C:\Temp\Mailboxes.csv'
|
||||
|
||||
# Create Exchange connection Uri from FQDN
|
||||
$exchangeConnectionUri = 'http://' + $exchangeServerFQDN +'/PowerShell/'
|
||||
|
||||
# Establish a session to Exchange
|
||||
$userCredential = Get-Credential
|
||||
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $exchangeConnectionUri -Authentication Kerberos -Credential $userCredential
|
||||
Import-PSSession $session -DisableNameChecking
|
||||
|
||||
# Get list of mailboxes
|
||||
$allMailboxes = Get-RemoteMailbox -ResultSize Unlimited | Where-Object {($_.PrimarySmtpAddress.Split('@')[1] -eq $primarySMTP)}
|
||||
|
||||
# Export results to CSV file
|
||||
$allMailboxes | Select-Object Name,Alias,UserPrincipalName,PrimarySmtpAddress,EmailAddresses | Export-Csv -Path $outputFile -NoTypeInformation
|
||||
|
||||
# End the Exchange Session
|
||||
Remove-PSSession -Session $session
|
||||
@@ -0,0 +1,15 @@
|
||||
# Exchange Online with AzureAD Connect
|
||||
|
||||
## What is this?
|
||||
|
||||
The scripts in this folder are for managing mailboxes in a synced environment, where you have an Exchange server on-prem purely for management purposes. This means all mailboxes are seen as "remote" mailboxes, so all the scripts use commands to that effect. These can easily be updated to a normal environment like on-prem only or cloud only just by removing the work "remote" from the commands. For example, Get-RemoteMailbox to just Get-Mailbox.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
These scripts require you to have on-prem Active Directory with an on-prem Exchange server for management, and using AzureAD Connect to sync to AzureAD.
|
||||
|
||||
It's pretty niche.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
All scripts are provided as is without warranty of any kind, use them at your own risk.
|
||||
@@ -0,0 +1,20 @@
|
||||
# Bulk change guest accounts from a certain domain so that they show in the Global Address List
|
||||
#
|
||||
# Uses the new PowerShell "module" that support MFA.
|
||||
#
|
||||
|
||||
# What domain are the guests email addresses from?
|
||||
$guestDomain = ''
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
# Find all the relevant users and enable them to show in the address list
|
||||
Get-MailUser -ResultSize Unlimited | Where-Object {$_.RecipientTypeDetails -eq 'GuestMailUser' -and $_.EmailAddresses -match $guestDomain} | Set-MailUser -HiddenFromAddressListsEnabled $false
|
||||
|
||||
# End the Exchange Session
|
||||
Get-PSSession | Where-Object {$_.ComputerName -eq 'outlook.office365.com'} | Remove-PSSession
|
||||
@@ -0,0 +1,42 @@
|
||||
# Create a group and add it to all room mailboxes as an editor
|
||||
#
|
||||
# Uses the new PowerShell "module" that support MFA.
|
||||
#
|
||||
|
||||
# What do you want the editors group to be called?
|
||||
$editorsGroup = 'Calendar Editors'
|
||||
|
||||
# Who do you want to be in the group? This can be 1 or more people.
|
||||
$editorsMembers = @('','')
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
# Get all room mailboxes in the organisation
|
||||
$roomMailboxes = (Get-Mailbox -RecipientTypeDetails RoomMailbox).Alias
|
||||
|
||||
# If the editors group doesn't exist, create it.
|
||||
if (!(Get-DistributionGroup -Identity $editorsGroup -ErrorAction SilentlyContinue)) {
|
||||
New-DistributionGroup -Name $editorsGroup -Type Security
|
||||
}
|
||||
|
||||
# Add members to the group
|
||||
$existingMembers = Get-DistributionGroupMember -Identity $editorsGroup
|
||||
foreach ($editorsMember in $editorsMembers) {
|
||||
if ($editorsMember -notin $existingMembers.Name) {
|
||||
Add-DistributionGroupMember -Identity $editorsGroup -Member $editorsMember
|
||||
}
|
||||
}
|
||||
|
||||
# Add the permissions to the mailboxes
|
||||
foreach ($roomMailbox in $roomMailboxes) {
|
||||
$calendarFolder = $mailboxAlias + ':\calendar'
|
||||
Add-MailboxFolderPermission -Identity $calendarFolder -User $editorsGroup -AccessRights Editor
|
||||
}
|
||||
|
||||
# End the Exchange Session
|
||||
Get-PSSession | Where-Object {$_.ComputerName -eq 'outlook.office365.com'} | Remove-PSSession
|
||||
@@ -0,0 +1,41 @@
|
||||
# Create a rule to block email forwarding to specific domains.
|
||||
#
|
||||
# Uses the new PowerShell "module" that support MFA.
|
||||
#
|
||||
|
||||
# What domains are we blocking?
|
||||
$domainListFile = 'C:\Temp\DomainList.txt'
|
||||
|
||||
# What do we want to call the rule?
|
||||
$ruleName = 'Block Auto Forwarding to Specific Domains 4'
|
||||
|
||||
# What reason do we want end users to see for the rejection?
|
||||
$rejectionReason = 'Auto forwarding messages to this email provider is not permitted.'
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
# Get the domain list from the file
|
||||
$domainList = Get-Content -Path $domainListFile
|
||||
|
||||
# Create a new rule
|
||||
$parameters = @{
|
||||
'Name' = $ruleName;
|
||||
'FromScope' = 'InOrganization';
|
||||
'SenderAddressLocation' = 'Header'
|
||||
'RecipientDomainIs' = $domainList;
|
||||
'MessageTypeMatches' = 'AutoForward';
|
||||
'RejectMessageEnhancedStatusCode' = '5.7.1'
|
||||
'RejectMessageReasonText' = $rejectionReason;
|
||||
'Priority' = 0;
|
||||
'Mode' = 'Enforce'
|
||||
'Enabled' = $true
|
||||
}
|
||||
New-TransportRule @parameters
|
||||
|
||||
# End the Exchange Session
|
||||
Get-PSSession | Where-Object {$_.ComputerName -eq 'outlook.office365.com'} | Remove-PSSession
|
||||
@@ -0,0 +1,91 @@
|
||||
# Script to bulk remove email proxy addresses from Exchange Online users
|
||||
#
|
||||
|
||||
# Which domains are we removing?
|
||||
$domainsToRemove = @('','')
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
### Remove the domain from mailboxes ###
|
||||
|
||||
# Get All Mailboxes
|
||||
$allMailboxes = Get-Mailbox -ResultSize Unlimited | Sort-Object -Property alias
|
||||
|
||||
# Remove alias from each mailbox
|
||||
foreach ($mailbox in $allMailboxes) {
|
||||
$redundantAddresses = @()
|
||||
foreach ($domainToRemove in $domainsToRemove) {
|
||||
$redundantAddresses += (($mailbox.EmailAddresses -split ',' | Where-Object {$_ -like ('*' + $domainToRemove + '*')}) -replace 'smtp:','')
|
||||
}
|
||||
if ($redundantAddresses.Count -gt 0) {
|
||||
Write-Output -InputObject ('Removing addresses ' + $redundantAddresses + ' from maibox ' + $mailbox.Name)
|
||||
Set-Mailbox -Identity $mailbox.Identity -EmailAddresses @{remove=$redundantAddresses} -Confirm:$false
|
||||
}
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
### Remove the domain from contacts ###
|
||||
|
||||
# Get all the contacts
|
||||
$allContacts = Get-MailContact -ResultSize Unlimited | Sort-Object -Property alias
|
||||
|
||||
# Remove alias from each contact
|
||||
foreach ($contact in $allContacts) {
|
||||
$redundantAddresses = @()
|
||||
foreach ($domainToRemove in $domainsToRemove) {
|
||||
$redundantAddresses += (($contact.EmailAddresses -split ',' | Where-Object {$_ -like ('*' + $domainToRemove + '*')}) -replace 'smtp:','')
|
||||
}
|
||||
if ($redundantAddresses.Count -gt 0) {
|
||||
Write-Output -InputObject ('Removing addresses ' + $redundantAddresses + ' from contact ' + $contact.Name)
|
||||
Set-MailContact -Identity $contact.Identity -EmailAddresses @{remove=$redundantAddresses} -Confirm:$false -ForceUpgrade:$true
|
||||
}
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
### Remove the domain from groups ###
|
||||
|
||||
# Get all the groups (this includes email enabled security groups)
|
||||
$allGroups = Get-DistributionGroup -ResultSize Unlimited | Sort-Object -Property alias
|
||||
|
||||
# Remove alias from each group
|
||||
foreach ($group in $allGroups) {
|
||||
$redundantAddresses = @()
|
||||
foreach ($domainToRemove in $domainsToRemove) {
|
||||
$redundantAddresses += (($group.EmailAddresses -split ',' | Where-Object {$_ -like ('*' + $domainToRemove + '*')}) -replace 'smtp:','')
|
||||
}
|
||||
if ($redundantAddresses.Count -gt 0) {
|
||||
Write-Output -InputObject ('Removing addresses ' + $redundantAddresses + ' from group ' + $group.Name)
|
||||
Set-DistributionGroup -Identity $group.Identity -EmailAddresses @{remove=$redundantAddresses} -Confirm:$false
|
||||
}
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
### Remove the domain from public folders ###
|
||||
|
||||
# Get all the groups (this includes email enabled security groups)
|
||||
$allPublicFolders = Get-MailPublicFolder -ResultSize Unlimited | Sort-Object -Property alias
|
||||
|
||||
# Remove alias from each public folder
|
||||
foreach ($publicFolder in $allPublicFolders) {
|
||||
$redundantAddresses = @()
|
||||
foreach ($domainToRemove in $domainsToRemove) {
|
||||
$redundantAddresses += (($publicFolder.EmailAddresses -split ',' | Where-Object {$_ -like ('*' + $domainToRemove + '*')}) -replace 'smtp:','')
|
||||
}
|
||||
if ($redundantAddresses.Count -gt 0) {
|
||||
Write-Output -InputObject ('Removing addresses ' + $redundantAddresses + ' from public folder ' + $publicFolder.Name)
|
||||
Set-MailPublicFolder -Identity $publicFolder.Identity -EmailAddresses @{remove=$redundantAddresses} -Confirm:$false
|
||||
}
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
# End the Exchange Session
|
||||
Get-PSSession | Where-Object {$_.ComputerName -eq 'outlook.office365.com'} | Remove-PSSession
|
||||
@@ -0,0 +1,20 @@
|
||||
# Enable Modern Authentication in Exchange Online
|
||||
#
|
||||
# Uses the new PowerShell "module" that support MFA.
|
||||
#
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
# Enable modern authentication
|
||||
Set-OrganizationConfig -OAuth2ClientProfileEnabled $true
|
||||
|
||||
# Verify the setting has changed
|
||||
Get-OrganizationConfig | Format-Table -AutoSize Name,OAuth2ClientProfileEnabled
|
||||
|
||||
# End the Exchange Session
|
||||
Get-PSSession | Where-Object {$_.ComputerName -eq 'outlook.office365.com'} | Remove-PSSession
|
||||
@@ -0,0 +1,29 @@
|
||||
# Enable mailbox auditing on mailboxes where auditing is not already enabled
|
||||
#
|
||||
# This is a rewrite of a script from https://github.com/OfficeDev/O365-InvestigationTooling
|
||||
#
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
# Set Auditing parameters
|
||||
$params = @{
|
||||
'AuditEnabled' = $true
|
||||
'AuditLogAgeLimit' = '180'
|
||||
'AuditAdmin' = @('Update','MoveToDeletedItems','SoftDelete','HardDelete','SendAs','SendOnBehalf','Create','UpdateFolderPermission')
|
||||
'AuditDelegate' = @('Update','SoftDelete','HardDelete','SendAs','Create','UpdateFolderPermissions','MoveToDeletedItems','SendOnBehalf')
|
||||
'AuditOwner' = @('UpdateFolderPermission','MailboxLogin','Create','SoftDelete','HardDelete','Update','MoveToDeletedItems')
|
||||
}
|
||||
|
||||
# Enable Auditing
|
||||
Get-Mailbox -ResultSize Unlimited | Where-Object {$_.RecipientTypeDetails -match '(User|Shared|Room|Discovery)Mailbox' -and $_.AuditEnabled -eq $false} | Set-Mailbox @params
|
||||
|
||||
# Check Auditing
|
||||
Get-Mailbox -ResultSize Unlimited | Where-Object {$_.RecipientTypeDetails -match '(User|Shared|Room|Discovery)Mailbox'} | Format-Table -AutoSize UserPrincipalName,RecipientTypeDetails,AuditEnabled,AuditLogAgeLimit
|
||||
|
||||
# End the Exchange Session
|
||||
Get-PSSession | Where-Object {$_.ComputerName -eq 'outlook.office365.com'} | Remove-PSSession
|
||||
@@ -0,0 +1,15 @@
|
||||
# Find mailboxes where UPN domain doesn't match email domain
|
||||
#
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
# Get list of mailboxes with a different mail domain to UPN domain
|
||||
Get-Mailbox -ResultSize Unlimited | Where-Object {$_.UserPrincipalName.Split('@')[1] -ne $_.PrimarySmtpAddress.Split('@')[1]} | Format-Table Name,UserPrincipalName,PrimarySmtpAddress,RecipientTypeDetails
|
||||
|
||||
# End the Exchange Session
|
||||
Get-PSSession | Where-Object {$_.ComputerName -eq 'outlook.office365.com'} | Remove-PSSession
|
||||
@@ -0,0 +1,40 @@
|
||||
# Find shared mailboxes on the basis of their email domain and lists of who has access to them
|
||||
#
|
||||
# Uses the new PowerShell "module" that support MFA.
|
||||
#
|
||||
|
||||
# Where to save the CSV files to
|
||||
$outputFile = 'C:\Temp\GroupDetails.csv'
|
||||
|
||||
# Wildcard for groups to find
|
||||
$searchWildcard = '*@example.domain'
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
# Get all the groups we're looking for
|
||||
$allGroups = Get-DistributionGroup | Where-Object {$_.PrimarySmtpAddress -like $searchWildcard}
|
||||
|
||||
# Initialise the hash table to store results in
|
||||
$groupDetails = @()
|
||||
|
||||
# Run through the groups getting the members and adding
|
||||
foreach ($group in $allGroups) {
|
||||
$groupMembers = (Get-DistributionGroupMember -Identity $group.Name).Alias -join '; '
|
||||
$groupDetails += [PSCustomObject]@{
|
||||
'GroupName' = $group.Name;
|
||||
'GroupEmail' = $group.PrimarySmtpAddress;
|
||||
'GroupType' = $group.GroupType;
|
||||
'GroupMembers' = $groupMembers
|
||||
}
|
||||
}
|
||||
|
||||
# Export results to CSV file
|
||||
$groupDetails | Export-Csv -Path $outputFile -NoTypeInformation
|
||||
|
||||
# End the Exchange Session
|
||||
Get-PSSession | Where-Object {$_.ComputerName -eq 'outlook.office365.com'} | Remove-PSSession
|
||||
@@ -0,0 +1,40 @@
|
||||
# Get the permissions and sendas rights for a list of mailboxes and output them to CSV
|
||||
#
|
||||
# Uses the new PowerShell "module" that support MFA.
|
||||
#
|
||||
|
||||
# Where to save the CSV files to
|
||||
$outputPath = 'C:\Temp\MailboxPermissions\'
|
||||
|
||||
# What mailboxes are we checking?
|
||||
$mailboxes = Get-Content -Path 'C:\Temp\Mailboxes.txt'
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
# Get all non-inherited mailbox permissions excluding self and output to a CSV file named for each mailbox
|
||||
foreach ($mailbox in $mailboxes) {
|
||||
Write-Output -InputObject ('Getting permissions for mailbox ' + $mailbox)
|
||||
$mailboxPermissions = Get-MailboxPermission -Identity $mailbox | Where-Object {$_.IsInherited -eq $false -and $_.User -ne 'NT AUTHORITY\SELF'} | Select-Object Identity,User,AccessRights,Deny
|
||||
if ($mailboxPermissions.Count -gt 0) {
|
||||
$outputFile = $outputPath + 'MailboxPermissions_' + ($mailbox -replace '@','_') + '.csv'
|
||||
$mailboxPermissions | Export-CSV -Path $outputFile -NoTypeInformation
|
||||
}
|
||||
}
|
||||
|
||||
# Get all non-inherited recipient permissions (sendas) excluding self and output to a CSV file named for each mailbox
|
||||
foreach ($mailbox in $mailboxes) {
|
||||
Write-Output -InputObject ('Getting permissions for recipient ' + $mailbox)
|
||||
$recipientPermissions = Get-RecipientPermission -Identity $mailbox | Where-Object {$_.IsInherited -eq $false -and $_.Trustee -ne 'NT AUTHORITY\SELF'} | Select-Object Identity,Trustee,AccessRights,AccessControlType
|
||||
if ($recipientPermissions.Count -gt 0) {
|
||||
$outputFile = $outputPath + 'RecipientPermissions_' + ($mailbox -replace '@','_') + '.csv'
|
||||
$recipientPermissions | Export-CSV -Path $outputFile -NoTypeInformation
|
||||
}
|
||||
}
|
||||
|
||||
# End the Exchange Session
|
||||
Get-PSSession | Where-Object {$_.ComputerName -eq 'outlook.office365.com'} | Remove-PSSession
|
||||
@@ -0,0 +1,32 @@
|
||||
# Find shared mailboxes on the basis of their email domain and lists of who has access to them
|
||||
#
|
||||
# Uses the new PowerShell "module" that support MFA.
|
||||
#
|
||||
|
||||
# Where to save the CSV files to
|
||||
$outputPath = 'C:\Temp\'
|
||||
|
||||
# Wildcard for mailboxes to find
|
||||
$searchWildcard = '*'
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
# Get all the mailboxes we're looking for
|
||||
$sharedMailboxes = Get-Mailbox -RecipientTypeDetails SharedMailbox -ResultSize Unlimited | Where-Object {$_.PrimarySmtpAddress -like $searchWildcard} | Select-Object Name,Alias,PrimarySmtpAddress,ProhibitSendQuota
|
||||
|
||||
# Export list of mailboxes to CSV File
|
||||
$sharedMailboxes | Export-CSV -Path ($outputPath + 'Shared Mailboxes.csv') -NoTypeInformation
|
||||
|
||||
# Get all non-inherited permissions excluding self and output to a CSV file named for each group
|
||||
foreach ($sharedMailbox in $sharedMailboxes) {
|
||||
$mailboxPermissions = Get-MailboxPermission -Identity $sharedMailbox.alias | Where-Object {$_.IsInherited -eq $false -and $_.User -ne 'NT AUTHORITY\SELF'} | Select-Object Identity,User,AccessRights,Deny
|
||||
$mailboxPermissions | Export-CSV -Path ($outputPath + $sharedMailbox.Name + '.csv') -NoTypeInformation
|
||||
}
|
||||
|
||||
# End the Exchange Session
|
||||
Get-PSSession | Where-Object {$_.ComputerName -eq 'outlook.office365.com'} | Remove-PSSession
|
||||
@@ -0,0 +1,27 @@
|
||||
# Exchange Online with MFA Support
|
||||
|
||||
## What is this?
|
||||
|
||||
Connecting to Exchange Online through a remote PowerShell session doesn't work when using multi factor authentication. You can (apparrently) get round that by creating an application password, but I've never got it to work and in my mind creating a password to bypass MFA somewhat defeates the point of enabling MFA in the first place.
|
||||
|
||||
There now is a new "module" available which does support MFA, so this folder is where I'll be putting new scripts that support MFA or old scripts as I update them.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
To connect using MFA you have to locally install a new module from Microsoft. Which for whatever reason isn't available from PSGallery, nor can it be simply downloaded. Instead it has to be installed from within the Exchange Online admin centre using one of those annoying ClickOnce installers that only work in MS's own web browsers.
|
||||
|
||||
Microsoft have a document explaining the unnecessarily convulted install process here:
|
||||
|
||||
[Connect to Exchange Online PowerShell using multi-factor authentication](https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/mfa-connect-to-exchange-online-powershell?view=exchange-ps)
|
||||
|
||||
In addition, because this will be using a remote session it will require the script execution policy within PowerShell to be changed to RemoteSigned. This is done either globally with:
|
||||
|
||||
`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned`
|
||||
|
||||
Or for the current user with:
|
||||
|
||||
`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`
|
||||
|
||||
## Disclaimer
|
||||
|
||||
All scripts are provided as is without warranty of any kind, use them at your own risk.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Reset default calendar permissions to availability for a list of users.
|
||||
#
|
||||
# Uses the new PowerShell "module" that support MFA.
|
||||
#
|
||||
|
||||
# File with list of users
|
||||
$userlistPath = 'C:\Temp\Userlist.txt'
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
# Get list of users
|
||||
$userlist = Get-Content -Path $userlistPath
|
||||
|
||||
# Get mailboxes for users in list
|
||||
$mailboxes = Get-Mailbox -ResultSize Unlimited | Where-Object {$_.Name -in $userlist} | Sort-Object -Property Name
|
||||
|
||||
# Check the mailboxes and reset any which have default permissions of None to AvailabilityOnly
|
||||
foreach ($mailbox in $mailboxes) {
|
||||
$calendarPath = $mailbox.UserPrincipalName + ':\Calendar'
|
||||
$defaultPermissions = Get-MailboxFolderPermission -Identity $calendarPath -User 'Default'
|
||||
if ($defaultPermissions.AccessRights -eq 'None') {
|
||||
Set-MailboxFolderPermission -Identity $calendarPath -User 'Default' -AccessRights AvailabilityOnly
|
||||
}
|
||||
}
|
||||
|
||||
# End the Exchange Session
|
||||
Get-PSSession | Where-Object {$_.ComputerName -eq 'outlook.office365.com'} | Remove-PSSession
|
||||
@@ -0,0 +1,28 @@
|
||||
# A simple script to enable forwarding for a list of users from a CSV file
|
||||
#
|
||||
# The script is expecting the CSV file to have two columns called SourceAddress and DestinationAddress
|
||||
#
|
||||
|
||||
# Get the list of users from a CSV file
|
||||
$userList = Import-Csv -Path 'C:\Temp\UserList.csv'
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
# Get all non-inherited permissions excluding self and output to a CSV file named for each group
|
||||
foreach ($user in $userList) {
|
||||
Write-Output -InputObject ('Forwarding ' + $user.SourceAddress + ' to ' + $user.DestinationAddress)
|
||||
Set-Mailbox -Identity $user.SourceAddress -ForwardingSmtpAddress $user.DestinationAddress
|
||||
}
|
||||
|
||||
# Pull back a list to check everything has worked correctly
|
||||
foreach ($user in $userList) {
|
||||
Get-Mailbox -Identity $user.SourceAddress | Select-Object UserPrincipalName,ForwardingSmtpAddress,DeliverToMailboxAndForward
|
||||
}
|
||||
|
||||
# End the Exchange Session
|
||||
Get-PSSession | Where-Object {$_.ComputerName -eq 'outlook.office365.com'} | Remove-PSSession
|
||||
@@ -0,0 +1,52 @@
|
||||
# Create and set up a room mailbox.
|
||||
#
|
||||
# Uses the new PowerShell "module" that support MFA.
|
||||
#
|
||||
|
||||
# New room name and alias
|
||||
$displayName = ''
|
||||
$mailboxAlias = ''
|
||||
|
||||
# How many people can the room take?
|
||||
$roomCapacity = ''
|
||||
|
||||
# Do you want meeting requests to be auto accepted?
|
||||
$requestAutoAccept = $true
|
||||
|
||||
# Do we want to add the room to a room list?
|
||||
$addToRoomList = $true
|
||||
|
||||
# What is the room list called? (Will be created if it doesn't exist)
|
||||
$roomList = ''
|
||||
|
||||
# Find and load the new ExO "module"
|
||||
$exoModulePath = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -Force -ErrorAction SilentlyContinue).DirectoryName[-1]
|
||||
. "$exoModulePath\CreateExoPSSession.ps1"
|
||||
|
||||
# Establish a session to Exchange Online
|
||||
Connect-EXOPSSession
|
||||
|
||||
# Create the new room mailbox
|
||||
New-Mailbox -Room -Alias $mailboxAlias -Name $displayName -DisplayName $displayName -ResourceCapacity $roomCapacity
|
||||
|
||||
# Wait for the meeting room mailbox to process
|
||||
Start-Sleep -Seconds 30
|
||||
|
||||
# Set the mailbox calendar to auto accept meeting requests (assuming policies are met)
|
||||
if ($requestAutoAccept) {
|
||||
Set-CalendarProcessing $mailboxAlias -AutomateProcessing AutoAccept
|
||||
}
|
||||
|
||||
# If we're adding the room to a room list, then do that.
|
||||
if ($addToRoomList) {
|
||||
# If the room list doesn't exist, create it.
|
||||
if (!(Get-DistributionGroup -Identity $roomList -ErrorAction SilentlyContinue)) {
|
||||
New-DistributionGroup -Name $roomList -RoomList
|
||||
}
|
||||
|
||||
# Add the room to the list
|
||||
Add-DistributionGroupMember -Identity $roomList -Member $mailboxAlias
|
||||
}
|
||||
|
||||
# End the Exchange Session
|
||||
Get-PSSession | Where-Object {$_.ComputerName -eq 'outlook.office365.com'} | Remove-PSSession
|
||||
@@ -0,0 +1,76 @@
|
||||
# ScheduledBitLockerKeyBackup.ps1
|
||||
|
||||
<#
|
||||
Script intended for deployment through Intune:
|
||||
Creates a locally saved PS script to get the bitlocker key and save it to Azure.
|
||||
Then creates a scheduled task to run that script at every logon.
|
||||
#>
|
||||
|
||||
# Name and description for the schedulled task to be created
|
||||
$taskName = 'Bitlocker Key Backup to AzureAD'
|
||||
$taskDescription = 'Retrieve Bitlocker key for system drive and store it in AzureAD'
|
||||
|
||||
# Day, time and randomised delay for the task to be created
|
||||
$taskDay = 'Monday'
|
||||
$taskTime = '12:00:00'
|
||||
$taskDelay = '00:20:00'
|
||||
|
||||
# Path to the folder for the files to be created
|
||||
$scriptFolder = 'C:\ProgramData\Intune\Scripts\'
|
||||
|
||||
# Names of the files to be created
|
||||
$scriptFilename = 'BitlockerKeyBackup.ps1'
|
||||
$scriptLogFilename = 'BitlockerKeyBackup-LastRun.log'
|
||||
$deployLogFilename = 'BitlockerKeyBackup-Deployed.log'
|
||||
|
||||
# Establish full paths to the files
|
||||
$scriptPath = $scriptFolder + $scriptFilename
|
||||
$logPath = $scriptFolder + $scriptLogFilename
|
||||
$deployLogPath = $scriptFolder + $deployLogFilename
|
||||
|
||||
# If folder doesn't exist create it, else clean up files from last run
|
||||
if (!(Test-Path -Path $scriptFolder)) {
|
||||
New-Item -Path $scriptFolder -ItemType Directory
|
||||
}
|
||||
else {
|
||||
foreach ($filePath in @($scriptPath, $logPath, $deployLogPath)) {
|
||||
if (Test-Path -Path $filePath) {
|
||||
Remove-Item -Path $filePath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Contents of the PS script file to be created on the target machine
|
||||
$scriptContents = @(
|
||||
'$logPath = ''' + $logPath + ''''
|
||||
'try {'
|
||||
' $recoveryPassword = ((Get-BitlockerVolume -MountPoint $env:SystemDrive -ErrorAction Stop).KeyProtector | Where-Object {$_.KeyProtectorType -eq "RecoveryPassword"})'
|
||||
' $result = BackupToAAD-BitLockerKeyProtector $env:systemdrive -KeyProtectorId $recoveryPassword.KeyProtectorId -ErrorAction Stop'
|
||||
' Out-File -InputObject $result -FilePath $logPath'
|
||||
'}'
|
||||
'catch {'
|
||||
' Out-File -InputObject $Error[0].Exception.Message -FilePath $logPath'
|
||||
'}'
|
||||
)
|
||||
|
||||
# Create the script file
|
||||
Out-File -InputObject $scriptContents -FilePath $scriptPath
|
||||
|
||||
# Set up the various parts of the scheduled task
|
||||
$taskArgument = '-ExecutionPolicy Bypass -Command ". ' + $scriptPath + '"'
|
||||
$taskAction = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument $taskArgument -WorkingDirectory $scriptFolder
|
||||
$taskTrigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek $taskDay -At $taskTime -RandomDelay $taskDelay
|
||||
$taskPrincipal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType 'ServiceAccount' -RunLevel 'Highest'
|
||||
$taskSettings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -Compatibility 'Win8' -Hidden -StartWhenAvailable
|
||||
|
||||
# If the scheduled task already exists then remove it
|
||||
if (Get-ScheduledTask | Where-Object { $_.TaskName -eq $taskName }) {
|
||||
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
|
||||
}
|
||||
|
||||
# Create the scheduled task and run it immediately
|
||||
$taskCreated = Register-ScheduledTask -Action $taskAction -Trigger $taskTrigger -TaskName $taskName -Description $taskDescription -Principal $taskPrincipal -Settings $taskSettings
|
||||
Start-ScheduledTask -TaskName $taskName
|
||||
|
||||
# Create a log file for the deployment of the scheduled task
|
||||
Out-File -InputObject $taskCreated -FilePath $deployLogPath
|
||||
@@ -0,0 +1,4 @@
|
||||
# Convert AD GUID to 365 ImmutableID
|
||||
|
||||
$adGuid = Read-Host -Prompt 'Enter Active Directory GUID to convert to ImmutableID'
|
||||
[System.Convert]::ToBase64String($adGuid.tobytearray())
|
||||
@@ -0,0 +1,22 @@
|
||||
# Bulk add a new licence to users on the basis of what licence they currently have
|
||||
#
|
||||
# This is useful for something like adding Office 365 ATP to everyone who currently has E3, for example.
|
||||
#
|
||||
|
||||
# What licence do the users currently have?
|
||||
$existingLicence = ''
|
||||
|
||||
# What licence are we adding?
|
||||
$licenceToAdd = ''
|
||||
|
||||
# Import MSOnline module and connect
|
||||
Import-Module MSOnline
|
||||
Connect-MsolService
|
||||
|
||||
# Find everyone who has the existing
|
||||
$users = Get-MsolUser -All | Where-Object {($_.licenses).AccountSkuId -match $existingLicence -and !(($_.licenses).AccountSkuId -match $licenceToAdd)}
|
||||
|
||||
# Add the new licence
|
||||
foreach ($user in $users) {
|
||||
Set-MSOLUserLicense -UserPrincipalName $user.UserPrincipalName –AddLicenses $licenceToAdd
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# Bulk add additional licences to a list of users where they already have a licence assigned.
|
||||
#
|
||||
# Only works where the user already has a licence assigned as assigning a licence to an unlicenced user is a different process.
|
||||
#
|
||||
|
||||
# Where is the list of user UPN's?
|
||||
$userListPath = 'C:\Temp\UserList.txt'
|
||||
|
||||
# What licences are we adding?
|
||||
# List of available SKUs can be obtained with (Get-MsolAccountSku).AccountSkuId
|
||||
$licencesToAdd = @('','')
|
||||
|
||||
# Import MSOnline module and connect
|
||||
Import-Module MSOnline
|
||||
Connect-MsolService
|
||||
|
||||
# Import list of users from file
|
||||
$users = Get-Content -Path $userListPath | Sort-Object
|
||||
|
||||
# Add the new licence
|
||||
foreach ($user in $users) {
|
||||
$userDetails = Get-MSOLUser -UserPrincipalName $user
|
||||
foreach ($licenceToAdd in $licencesToAdd) {
|
||||
if ($userDetails.IsLicensed -eq $true) {
|
||||
if (!(($userDetails.licenses).AccountSkuId -match $licenceToAdd)) {
|
||||
Write-Output -InputObject ('Adding Licence ' + $licenceToAdd + ' to ' + $user + '.')
|
||||
Set-MSOLUserLicense -UserPrincipalName $user –AddLicenses $licenceToAdd
|
||||
}
|
||||
else {
|
||||
Write-Output -InputObject ('User ' + $user + ' already has ' + $licenceToAdd + ' licence assigned.')
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Output -InputObject ('User ' + $user + ' has no existing licence assigned.')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
# Bulk enable or disable MFA for all users in a tenant
|
||||
#
|
||||
|
||||
# Enable or disable MFA?
|
||||
$enableMFA = $true
|
||||
|
||||
# Import MSOnline module and connect
|
||||
Import-Module MSOnline
|
||||
Connect-MsolService
|
||||
|
||||
# Enable or disable MFA
|
||||
if ($enableMFA) {
|
||||
# Create an object containing the authentication requirements
|
||||
$authReq = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
|
||||
|
||||
# Include all relying parties
|
||||
$authReq.RelyingParty = '*'
|
||||
|
||||
# Set MFA state to enabled
|
||||
# Enabled allows connected apps to keep working until the user completes MFA set up.
|
||||
# This can also be set to enforced which would disconnect everything immediately.
|
||||
$authReq.State = 'Enabled'
|
||||
|
||||
# Set the cut off date before which registered devices should require re-connecting with MFA.
|
||||
# Using the current date is recommended so that all previously connected devices have to be reconnected.
|
||||
$authReq.RememberDevicesNotIssuedBefore = (Get-Date)
|
||||
|
||||
# Find all licenced users who do not currently have MFA enabled or enforced
|
||||
$usersToChange = Get-MsolUser | Where-Object {$_.StrongAuthenticationRequirements.State -notmatch 'Enabled|Enforced' -and $_.isLicensed -eq $true}
|
||||
|
||||
# Enable MFA for those users
|
||||
$usersToChange | Set-MsolUser -StrongAuthenticationRequirements $authReq
|
||||
}
|
||||
else {
|
||||
# Find all licenced users who currently have MFA enabled or enforced
|
||||
$usersToChange = Get-MsolUser | Where-Object {$_.StrongAuthenticationRequirements.State -match 'Enabled|Enforced' -and $_.isLicensed -eq $true}
|
||||
|
||||
# Disable MFA for those users
|
||||
$usersToChange | Set-MsolUser -StrongAuthenticationRequirements @()
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# Bulk update Online User UPNs
|
||||
#
|
||||
|
||||
# What domain are we replacing?
|
||||
$oldDomain = ''
|
||||
|
||||
# What are we replacing it with?
|
||||
$newDomain = ''
|
||||
|
||||
# Import the MSOnline module and connect
|
||||
Import-Module MSOnline
|
||||
Connect-MsolService
|
||||
|
||||
# Get all users using that domain as their UPN
|
||||
$users = Get-MsolUser -All | Where-Object {$_.UserPrincipalName -match $oldDomain}
|
||||
|
||||
# Run through the users replacing their UPN and keeping us updated on what's going on
|
||||
foreach ($user in $users) {
|
||||
$newUPN = $user.UserPrincipalName.Split('@')[0] + '@' + $newDomain
|
||||
Write-Output -InputObject ('Setting UPN for user ' + $user.UserPrincipalName + ' to ' + $newUPN)
|
||||
Set-MsolUserPrincipalName -UserPrincipalName $user.UserPrincipalName -NewUserPrincipalName $newUPN
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# Disable MFA for all licenced users who currently have it enabled
|
||||
#
|
||||
|
||||
# Import MSOnline module and connect
|
||||
Import-Module MSOnline
|
||||
Connect-MsolService
|
||||
|
||||
# Find all licenced users who currently have MFA enabled or enforced
|
||||
$usersToChange = Get-MsolUser | Where-Object {$_.StrongAuthenticationRequirements.State -match 'Enabled|Enforced' -and $_.isLicensed -eq $true}
|
||||
|
||||
# Disable MFA for those users
|
||||
$usersToChange | Set-MsolUser -StrongAuthenticationRequirements @()
|
||||
@@ -0,0 +1,26 @@
|
||||
# Enable MFA for all licenced users who don't currently have it enabled
|
||||
#
|
||||
|
||||
# Import MSOnline module and connect
|
||||
Import-Module MSOnline
|
||||
Connect-MsolService
|
||||
|
||||
# Create an object containing the authentication requirements
|
||||
$authReq = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
|
||||
|
||||
# Include all relying parties
|
||||
$authReq.RelyingParty = '*'
|
||||
|
||||
# Set MFA state to enabled
|
||||
# Enabled allows connected apps to keep working until the user completes MFA set up.
|
||||
# This can also be set to enforced which would disconnect everything immediately.
|
||||
$authReq.State = 'Enabled'
|
||||
|
||||
# Set the cut off date before which registered devices should require re-connecting with MFA
|
||||
$authReq.RememberDevicesNotIssuedBefore = (Get-Date)
|
||||
|
||||
# Find all licenced users who do not currently have MFA enabled or enforced
|
||||
$usersToChange = Get-MsolUser | Where-Object {$_.StrongAuthenticationRequirements.State -notmatch 'Enabled|Enforced' -and $_.isLicensed -eq $true}
|
||||
|
||||
# Enable MFA for those users
|
||||
$usersToChange | Set-MsolUser -StrongAuthenticationRequirements $authReq
|
||||
@@ -0,0 +1,17 @@
|
||||
# Bulk remove a licence from users
|
||||
#
|
||||
|
||||
# What licence are we removing?
|
||||
$licenceToRemove = ''
|
||||
|
||||
# Import MSOnline module and connect
|
||||
Import-Module MSOnline
|
||||
Connect-MsolService
|
||||
|
||||
# Find everyone who has the licence to be removed
|
||||
$users = Get-MsolUser -All | Where-Object {($_.licenses).AccountSkuId -match $licenceToRemove}
|
||||
|
||||
# Remove the licence
|
||||
foreach ($user in $users) {
|
||||
Set-MSOLUserLicense –user $user.UserPrincipalName –RemoveLicenses $licenceToRemove
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
# Bulk replace a licence for all users who have the one being replaced.
|
||||
#
|
||||
|
||||
# What licence are we removing?
|
||||
$licenceToRemove = ''
|
||||
|
||||
# What licence are we adding?
|
||||
$licenceToAdd = ''
|
||||
|
||||
# Import MSOnline module and connect
|
||||
Import-Module MSOnline
|
||||
Connect-MsolService
|
||||
|
||||
# Find everyone who has the licence being replaced
|
||||
$users = Get-MsolUser -All | Where-Object {($_.licenses).AccountSkuId -match $licenceToRemove}
|
||||
|
||||
# Remove the old licence and add the new one
|
||||
foreach ($user in $users) {
|
||||
Set-MSOLUserLicense –user $user.UserPrincipalName –RemoveLicenses $licenceToRemove
|
||||
Set-MSOLUserLicense –user $user.UserPrincipalName -AddLicenses $licenceToAdd
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
# Update Online User UPN - when AD sync doesn't do it.
|
||||
|
||||
# Import the MSOL module and connect
|
||||
Import-Module MSOnline
|
||||
Connect-MsolService
|
||||
|
||||
# Whose UPN are we changing?
|
||||
$oldUPN = Read-Host -Prompt 'Enter user''s old UPN in the format username@domain'
|
||||
|
||||
# What are we changing it to?
|
||||
$newUPN = Read-Host -Prompt 'Enter user''s new UPN in the format username@domain'
|
||||
|
||||
# Change the UPN
|
||||
if (Get-ADUser -Identity $newUPN.Split('@')[0]) {
|
||||
Set-MsolUserPrincipalName -UserPrincipalName $oldUPN -NewUserPrincipalName $newUPN
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# Delete a user and then delete the deleted user
|
||||
|
||||
Import-Module MSOnline
|
||||
Connect-MsolService
|
||||
|
||||
$upnToDelete = Read-Host -Prompt 'Enter UPN of user to delete in the format username@domain'
|
||||
|
||||
Remove-MsolUser -UserPrincipalName $upnToDelete
|
||||
Remove-MsolUser -UserPrincipalName $upnToDelete -RemoveFromRecycleBin
|
||||
@@ -0,0 +1,33 @@
|
||||
# Remove a duplicate 365 account created by a faulty sync and reconnect
|
||||
# the orphaned 365 user to the AD account.
|
||||
#
|
||||
|
||||
# Get correct and incorrect account details
|
||||
$adUsername = Read-Host -Prompt 'Enter username for AD account'
|
||||
$msolIncorrectUPN = Read-Host -Prompt 'Enter UPN for the duplicate object in MSOL'
|
||||
|
||||
# Connect to MS Online
|
||||
Import-Module MSOnline
|
||||
Connect-MsolService
|
||||
|
||||
# Get AD user account
|
||||
$adObject = Get-ADUser -Identity $adUsername
|
||||
|
||||
# Get correct UPN from AD account
|
||||
$msolCorrectUPN = $adObject.UserPrincipalName
|
||||
|
||||
#
|
||||
try {
|
||||
Get-MsolUser -UserPrincipalName $msolCorrectUPN -ErrorAction Stop
|
||||
|
||||
Remove-MSOLuser -UserPrincipalName $msolIncorrectUPN
|
||||
Remove-MSOLuser -UserPrincipalName $msolIncorrectUPN -RemoveFromRecycleBin
|
||||
|
||||
$adGuid = $adObject.ObjectGuid
|
||||
$immutableID = [System.Convert]::ToBase64String($adGuid.ToByteArray())
|
||||
|
||||
Set-MSOLuser -UserPrincipalName $msolCorrectUPN -ImmutableID $immutableID
|
||||
}
|
||||
catch {
|
||||
Write-Host 'No account found in Azure AD matching the UPN for that AD account.'
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# Convert 365 ImmutableID to AD GUID
|
||||
|
||||
$immutableID = Read-Host -Prompt 'Enter ImmutableID to convert to Active Directory GUID'
|
||||
[GUID][System.Convert]::FromBase64String($immutableID)
|
||||
@@ -0,0 +1,18 @@
|
||||
# Retrive a list of all OneDrive for Business sites within the organisation
|
||||
#
|
||||
# Requires the Sharepoint Online PowerShell module to be installed
|
||||
#
|
||||
|
||||
# The name of your Office 365 organization
|
||||
# This can be found in your Sharepoint URL before the '-my', eg: https://thecompany-my.sharepoint.com/
|
||||
$spoTenantName=''
|
||||
|
||||
# Connect to Sharepoint Online
|
||||
Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking
|
||||
Connect-SPOService -Url ('https://' + $spoTenantName + '-admin.sharepoint.com')
|
||||
|
||||
# Create the common base URL for OneDrive for Business
|
||||
$spoBaseWildcard = 'https://' + $spoTenantName + '-my.sharepoint.com/personal/*'
|
||||
|
||||
# Get a list of all 'personal' sites (e.g.: OneDrive for Business sites) within the tenant
|
||||
Get-SPOSite -Limit all -IncludePersonalSite $true | Where-Object {$_.Url -like $spoBaseWildcard} | Select-Object Owner,URL,StorageQuota | Format-Table -AutoSize
|
||||
@@ -0,0 +1,47 @@
|
||||
# Increase the size of specific users' OneDrive for Business accounts
|
||||
#
|
||||
# Requires the Sharepoint Online PowerShell module to be installed
|
||||
#
|
||||
|
||||
# The name of your Office 365 organization
|
||||
# This can be found in your Sharepoint URL before the '-my', eg: https://thecompany-my.sharepoint.com/
|
||||
$spoTenantName=''
|
||||
|
||||
# The size you want to increase to in TB.
|
||||
$newSize = 1
|
||||
|
||||
# The list of UPNs for the accounts you wich to add the secondary admin to (list can contain a single item if required)
|
||||
$userList = @('','')
|
||||
|
||||
# Connect to Sharepoint Online
|
||||
Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking
|
||||
Connect-SPOService -Url ('https://' + $spoTenantName + '-admin.sharepoint.com')
|
||||
|
||||
# Create the base URL for OneDrive for Business
|
||||
$spoBaseURL = 'https://' + $spoTenantName + '-my.sharepoint.com/personal/'
|
||||
|
||||
# Convert new size to bytes
|
||||
$newBytes = $newSize * 1048576
|
||||
|
||||
# Increase size for each user in list
|
||||
foreach ($userUPN in $userList) {
|
||||
$spoURL = $spoBaseURL + ($userUPN.ToLower() -replace "[@.]", "_")
|
||||
try {
|
||||
$currentBytes = (Get-SPOSite -Identity $spoURL -ErrorAction:Stop).StorageQuota
|
||||
if ($currentBytes -gt $newBytes) {
|
||||
try {
|
||||
Set-SPOSite -Identity $spoURL -StorageQuota $newBytes -ErrorAction:Stop
|
||||
Write-Output -InputObject ('Updated OneDrive account limit for ' + $userUPN + ' to ' + $newSize + 'TB.')
|
||||
}
|
||||
catch {
|
||||
Write-Output -InputObject ('Failed to update OneDrive account limit for ' + $userUPN + '.')
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Output -InputObject ('OneDrive account limit for ' + $userUPN + ' already equal to or higher than ' + $newSize + 'TB.')
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Output -InputObject ('No OneDrive account found for ' + $userUPN + '.')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
# Increase the size of all users' OneDrive for Business accounts
|
||||
#
|
||||
# Requires the Sharepoint Online PowerShell module to be installed
|
||||
#
|
||||
|
||||
# The name of your Office 365 organization
|
||||
# This can be found in your Sharepoint URL before the '-my', eg: https://thecompany-my.sharepoint.com/
|
||||
$spoTenantName=''
|
||||
|
||||
# The size you want to increase to in TB.
|
||||
$newSize = 1
|
||||
|
||||
# Connect to Sharepoint Online
|
||||
Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking
|
||||
Connect-SPOService -Url ('https://' + $spoTenantName + '-admin.sharepoint.com')
|
||||
|
||||
# Create the common base URL for OneDrive for Business
|
||||
$spoBaseWildcard = 'https://' + $spoTenantName + '-my.sharepoint.com/personal/*'
|
||||
|
||||
# Convert new size to bytes
|
||||
$newBytes = $newSize * 1048576
|
||||
|
||||
# Get a list of all personal sites within the tenant.
|
||||
$personalSites = Get-SPOSite -Limit all -IncludePersonalSite $true | Where-Object {$_.Url -like $spoBaseWildcard}
|
||||
|
||||
# Increase size for each user in turn.
|
||||
foreach ($personalSite in $personalSites) {
|
||||
$spoURL = $personalSite.Url
|
||||
$userUPN = $personalSite.Owner
|
||||
$currentBytes = $personalSite.StorageQuota
|
||||
|
||||
if ($currentBytes -lt $newBytes) {
|
||||
try {
|
||||
Set-SPOSite -Identity $spoURL -StorageQuota $newBytes -ErrorAction:Stop
|
||||
Write-Output -InputObject ('Updated OneDrive account limit for ' + $userUPN + ' to ' + $newSize + 'TB.')
|
||||
}
|
||||
catch {
|
||||
Write-Output -InputObject ('Failed to update OneDrive account limit for ' + $userUPN + '.')
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Output -InputObject ('OneDrive account limit for ' + $userUPN + ' already equal to or higher than ' + $newSize + 'TB.')
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user